WPF TreeView 隐藏项目的虚拟化性能

eng*_*mtm 1 c# wpf treeview virtualization

我有一个TreeView控件,允许用户根据关键字过滤树中的项目。VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"我的树上有它并且它ItemsSource是数据绑定的。我TreeViewItemVisibility设置如下:

<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>

该树在未过滤时的性能非常好,但在加载具有大量隐藏项目的树项目时,我发现性能受到很大影响。从我在 VS 的诊断工具中看到的情况来看,在我看来,MyTreeViewItem试图加载它的不可见子项,即使它们不可见,这会导致内存和 CPU 因加载大量不可见项而受到影响。有谁之前经历过这个吗?有没有办法可以覆盖实现虚拟树项目的默认逻辑,以便隐藏项目不会被加载?

Grx*_*x70 6

此行为是预期的。

假设您的收藏中有 10000 件物品。前 5000 名已IsVisible设置为false。启用 UI 虚拟化后,会生成容器,直到填满可用空间。所以你最终会得到 5000 个折叠的TreeViewItems (它们不占用空间)加上几个填充可用空间的。我希望你能明白问题出在哪里。

我认为最好的选择是使用Live Shaping (在WPF 4.5中提供)。基本思想是从源集合视图中过滤掉不可见的项目,以便不会为这些项目生成容器。

简而言之,而不是

<TreeView ItemsSource="{Binding Items}">
</TreeViewitem>
Run Code Online (Sandbox Code Playgroud)

您可以使用以下设置:

<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>
Run Code Online (Sandbox Code Playgroud)

private void Items_Filter(object sender, FilterEventArgs e)
{
    var item = (YourItemType)e.Item;
    e.Accepted = item.IsVisible;
}
Run Code Online (Sandbox Code Playgroud)

您还必须将相同的技巧应用于HierarchicalDataTemplate.ItemsSource. 其作用是设置一个集合视图,用于侦听IsVisible属性的更改并在必要时重新应用过滤器(如果您使用的是4.5之前的WPF版本,则必须手动执行此操作)。