使用VirtualizationMode.Recycling时,TreeView错误地将项目显示为已展开

时间:2013-09-22 18:16:42

标签: wpf treeview virtualization ui-virtualization

每当我使用TreeView时,我总是只有几个节点,每个节点通常少于100个项目。我从来没有真正需要任何类型的虚拟化,但现在我第一次需要它。

当在回收模式下使用ui虚拟化时出现问题,即使我从未手动扩展它们,TreeView似乎也会扩展项目。

我搜索了这个问题,到目前为止,我了解了TreeView中的虚拟化回收模式,容器可以重复使用。

所以我假设原因可能是已将扩展的重用容器应用于之前未展开的项目。

这是一个简单的例子:

https://github.com/devhedgehog/wpf/

对于那些因任何原因无法下载代码的人来说,这基本上就是我尝试用TreeView做的。

这就是我在XAML中所拥有的。

     <Grid>
        <TreeView ItemsSource="{Binding}" VirtualizingStackPanel.IsVirtualizing="True"  VirtualizingStackPanel.VirtualizationMode="Recycling">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Parts}">
                    <TextBlock Text="{Binding Name}"/>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}"/>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>

这就是背后的代码:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            IList<Car> list = new List<Car>();
            for (int i = 0; i < 5000; i ++)
            {
                list.Add(new Car() { Name = "test1" + i });
            }

            foreach (var car in list)
            {
                car.Parts = new List<string>();
                for (int i = 0; i < 500; i++)
                {
                    car.Parts.Add("asdf" + i);
                }
            }

            this.DataContext = list;
        }
    }

    public class Car
    {
        public string Name
        {
            get;
            set;
        }

        public List<string> Parts
        {
            get;
            set;
        }
    }

我希望有人能为我提供这个问题的解决方案。这是一个已知的错误吗?

如果有重复,我很抱歉。此外,我希望你们告诉我我做错了什么,因为这是我在降级问题之前的第一篇文章。

1 个答案:

答案 0 :(得分:3)

您可能知道,使用标准回收模式可以轻松解决此问题:

<TreeView VirtualizingStackPanel.VirtualizationMode="Standard" ...>

这不会对TreeView的性能产生太大影响,因为树仍将被虚拟化,并且只会为可见项创建容器。回收模式的好处只有在滚动时才能发挥作用(当项目都被虚拟化和实现时),并且标准虚拟化模式通常都足够好。

但是,如果性能非常关键(或者如果你真的需要一个解决方案,同时保持回收模式,或者你想以正确的方式做事),你可以使用支持数据和数据绑定到解决这个问题。

首先出现此问题的原因是:

假设您有一个TreeViewItem,其IsExpanded属性设置为true。当它被回收,即它的数据被替换时,它的IsExpanded属性保持不变,因为它无法知道它是否应该被扩展,因为该数据在任何地方都不可用。唯一存在的地方是IsExpanded的{​​{1}}属性,它不会相关,因为该项目正在与其属性一起重用。

但是,如果您有每个树项的视图模型,则可以将每个TreeViewItem绑定到TreeViewItem中的IsExpanded属性(每个树视图都有一个视图模型)树项目),您将始终获得正确的值,因为您已经提供了这些数据并将每个项目绑定到它。

您的TreeView的TreeViewItemViewModel将绑定到ItemsSource个对象的集合,您的TreeViewItemViewModel类将如下所示:

TreeViewItemViewModel

您可以在Josh Smith的优秀文章Simplifying the WPF TreeView by Using the ViewModel Pattern中找到有关如何创建此类视图模型的更多信息。