Виртуализация вложенных контейнеров (virtualizingstackpanel) на одной родительской полосе прокрутки в WPF
Я как бы закодировал себя в этом. Я пишу пользовательский элемент управления WPF, который похож на TreeListView
описано в этой статье MSDN, а также во многих других местах в сети. На данный момент довольно большая куча этой вещи - обычай, и она вполне соответствует моим целям, за исключением виртуализации. Мой переопределенный TreeView
а также TreeViewItem
оба шаблона используют VirtualizingStackPanel
s, чтобы представить свои предметы, и я убедился, что все это создается, как и ожидалось. Виртуализация работает правильно на элементах корневого уровня (только элементы пользовательского интерфейса для тех, которые в настоящее время видны в ScrollViewer
приготовлены), а TreeView
вещи заботятся о том, чтобы не генерировать элементы для свернутых узлов. Проблема возникает при расширении узла - все элементы готовятся для каждого дочернего узла, даже тысячи, которые находятся за пределами экрана.
Мне казалось, что все, что мне нужно было сделать - это установить свойство scrollowner для внутреннего вложенного элемента. VirtualizingStackPanel
s к тому же основному представлению прокрутки, к которому VSP корневого уровня подключен по умолчанию, но я прочитал плакат MSFT, в котором говорится, что это не будет работать.
К сожалению, эта штука медленна, как грязь, без виртуализации, поэтому мне нужно найти какое-то решение. Любые предложения будут ценны.
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, чтобы доказать, что это виртуализация пользовательского интерфейса. Вот количество загруженных TreeViewItem
Когда приложение маленькое:
... а вот количество загруженных TreeViewItem
Когда приложение работает в полноэкранном режиме (оно выходит за рамки этого фрагмента, но вы поняли):
Теперь нужно просто стилизовать вещи так, чтобы вложенный слой выглядел так, как я хочу!
Изменить: я только что подтвердил, что TreeView
виртуализирует все его слои, а не только первый.
У меня была ссылка на список того, чего не следует делать с виртуализированной стековой панелью, но по какой-то причине страница оказалась пустой. Вот еще одна страница, которая немного говорит об этом:
http://www.designerwpf.com/2008/02/12/listview-and-listbox-performance-issues/
и даже ссылки на тот, о котором я говорю, но он всегда пуст. если вы посмотрите на эту страницу, это ссылка на блог Марка Шурмера. Вот ссылка, если вы хотите попробовать это:
http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/
У Bea Stollnitz также есть несколько статей, которые могут помочь:
Если вы опубликуете часть своего кода, кто-то может немного разгадать спагетти, чтобы помочь вам получить лучшую реализацию.
РЕДАКТИРОВАТЬ: нашел ссылку, которая может работать (спасибо archive.org!!!): http://web.archive.org/web/20080104163725/http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/