我有一个TreeView
控件,我允许用户根据关键字过滤树的项目。我的树上有VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"
,其ItemsSource
是数据绑定的。我的TreeViewItem
Visibility
设置如下:
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
当树没有被过滤时,树的表现非常好,但是在加载具有大量隐藏项的树项时,我看到了很大的性能损失。从我在VS的诊断工具中可以看到,在我看来,My TreeViewItem
尝试加载它的隐形子项,即使它们不可见,这也导致内存和CPU大量的加载了隐形物品。有谁之前经历过这个吗?有没有办法可以覆盖实现虚拟树项的默认逻辑,这样隐藏的项就不会被加载?
答案 0 :(得分:2)
此行为是预期的。
假设您的收藏品中有10000件商品。 First 5000将IsVisible
设置为false
。启用UI虚拟化后,将生成容器,直到它们填满可用空间。所以你最终得到5000折叠TreeViewItem
(他们没有空间)加上一对填满可用空间的人。我希望你能看出问题所在。
我认为您最好的选择是使用 Live Shaping (可在 WPF 4.5中找到)。基本思想是从源集合视图中过滤掉不可见的项目,以便不为这些项目生成容器。
简而言之,而不是
<TreeView ItemsSource="{Binding Items}">
</TreeViewitem>
您可以使用以下设置:
<TreeView>
<FrameworkElement.Resources>
<CollectionViewSource x:Key="Items"
Source="{Binding Items}"
Filter="Items_Filter"
IsLiveFilteringRequested="True"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<CollectionViewSource.LiveFilteringProperties>
<sys:String>IsVisible</sys:String>
</CollectionViewSource.LiveFilteringProperties>
</CollectionViewSource>
</FrameworkElement.Resources>
<ItemsControl.ItemsSource>
<Binding Source="{StaticResource Items}" />
</ItemsControl.ItemsSource>
</TreeView>
和
private void Items_Filter(object sender, FilterEventArgs e)
{
var item = (YourItemType)e.Item;
e.Accepted = item.IsVisible;
}
您还必须对HierarchicalDataTemplate.ItemsSource
应用相同的技巧。
这样做是设置一个集合视图来监听IsVisible
属性中的更改并在必要时重新应用过滤器(如果您在 4.5之前使用 WPF 版本你必须手动完成。