виртуализация вложенных контейнеров (virtualizingstackpanel) в одну родительскую полосу прокрутки в WPF

Я как бы закодировал себя в рассоле на этом. Я пишу собственный элемент управления WPF, который похож на TreeListView, описанный в Эта статья MSDN, а также многие другие места в сети. На данный момент довольно большая куча этой штуки изготовлена ​​по индивидуальному заказу, и она достаточно хорошо соответствует моим целям, за исключением виртуализации. Мои переопределенные шаблоны TreeView и TreeViewItem используют VirtualizingStackPanel для представления своих элементов, и я убедился, что все это создается, как и ожидалось. Виртуализация корректно работает с элементами корневого уровня (подготавливаются только элементы пользовательского интерфейса для тех, которые в настоящее время видны в ScrollViewer), а материал TreeView заботится о том, чтобы не генерировать элементы для свернутых узлов. Проблема возникает при расширении узла — все элементы создаются для каждого дочернего элемента в узле, даже для тысяч, которые находятся за пределами экрана.

Мне казалось, что все, что мне нужно было сделать, это каким-то образом установить для свойства scrollowner внутренних вложенных VirtualizingStackPanel тот же основной вид прокрутки, к которому по умолчанию подключается VSP корневого уровня, но я прочитал постер MSFT здесь говорит, что это не сработает.

К сожалению, без виртуализации эта вещь работает медленно, как грязь, поэтому мне нужно придумать какое-то решение. Любые предложения будут ценны.


person David Hay    schedule 30.07.2009    source источник
comment
Я знаю, что это было давно, но вы помните, что вы сделали, чтобы обойти это?   -  person Matt Thomas    schedule 16.03.2017
comment
Я только что понял, что учетная запись Дэвида какое-то время неактивна. Так что для тех, кто придет после меня, см. мой ответ ниже   -  person Matt Thomas    schedule 16.03.2017


Ответы (2)


Я знаю, что это старый вопрос, но он все еще актуален для меня.

В моем случае я думал, что TreeView не урежет его, потому что мне нужно ровно два слоя, а типы отображаемых элементов различаются между двумя слоями. Кроме того, я рефакторинг списка Expander, поэтому я думал более одномерно.

Но потом я понял, что вы можете настроить ItemTemplate из TreeView, чтобы включить свои собственные HierarchicalDataTemplate, и что вы можете настроить ItemTemplate этого HierarchicalDataTemplate с вашими собственными настройками DataTemplate... Готово! Ровно два слоя с разными вещами в каждом!

Итак, я хочу сказать, что TreeView достаточно гибок, поэтому вам не следует создавать собственный настраиваемый элемент управления.

Вот что я сделал:

XAML:

<Page x:Class="Foo.Views.TreePage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Foo.Views"
      xmlns:viewModel="clr-namespace:Foo.ViewModels"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
      Title="Tree page"
      d:DataContext="{d:DesignInstance Type=viewModel:TreeModel}">
    <TreeView
        VirtualizingPanel.IsVirtualizing="True"
        VirtualizingPanel.VirtualizationMode="Recycling"
        ScrollViewer.CanContentScroll="True"
        VirtualizingPanel.ScrollUnit="Pixel"
        ItemsSource="{Binding Values}"><!-- IList<Person> -->
        <TreeView.ItemTemplate><!-- Template for first layer, which has a HierarchicalDataTemplate so that this layer will expand -->
            <HierarchicalDataTemplate
                ItemsSource="{Binding Expenses}"><!-- IList<Expense> -->
                <HierarchicalDataTemplate.ItemTemplate><!-- Template for the second layer, which has a DataTemplate instead of HierarchicalDataTemplate so that this layer won't expand -->
                    <DataTemplate>
                        <TextBlock Text="{Binding Amount}"/><!-- Expense amount in dollars -->
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>

                <TextBlock Text="{Binding Name}"/><!-- Person name -->
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Page>

Класс Person:

public class Person
{
    public string Name { get; set; }
    public List<Expense> Expenses { get; set; }
}

Класс Expense:

public class Expense
{
    public double Amount { get; set; }
}

Вот как это выглядит:

Скриншот приведенного выше кода в действии

Я проверил его с помощью Snoop, чтобы доказать, что это виртуализация пользовательского интерфейса. Вот количество загруженных TreeViewItems, когда приложение маленькое:

Скриншот, показывающий количество элементов, когда приложение маленькое

...А вот количество загруженных TreeViewItems, когда приложение находится в полноэкранном режиме (оно продолжается дальше этого фрагмента, но вы поняли идею):

Скриншот, показывающий, что в полноэкранном режиме появляется больше элементов

Теперь осталось только стилизовать вещи, чтобы вложенный слой выглядел так, как я хочу!

Редактировать: я только что убедился, что TreeView виртуализирует все свои слои, а не только первый слой.

person Matt Thomas    schedule 16.03.2017

У меня была ссылка на список того, что нельзя делать с панелью стека виртуализации, но по какой-то причине страница оказывается пустой. Вот еще одна страница, которая немного говорит об этом:

http://www.designerwpf.com/2008/02/12/listview-and-listbox-performance-issues/

и даже ссылки на тот, о котором я говорю, но он всегда пустой. если вы посмотрите на эту страницу, это ссылка на блог Марка Шурмера. Вот ссылка, если хотите попробовать:

http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/

У Беа Столльниц также есть несколько статей, которые могут помочь:

Часть 1 Часть 2 Часть 3

Если вы опубликуете часть своего кода, кто-то сможет немного разгадать спагетти, чтобы помочь вам добиться лучшей реализации.

РЕДАКТИРОВАТЬ: Нашел ссылку, которая может работать (спасибо, archive.org!!!): http://web.archive.org/web/20080104163725/http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/

person Mark Synowiec    schedule 30.07.2009