2

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

当使用具有回收模式的 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;
        }
    }

我希望有人可以为我提供解决此问题的方法。这是一个已知的错误?

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

4

1 回答 1

3

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

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

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

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

首先出现这个问题的原因是这样的:

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

但是,如果您对每个树项都有一个视图模型,那么您将能够将每个视图模型绑定TreeViewItemIsExpanded您的属性TreeViewItemViewModel(每个树项都有一个视图模型),并且您将始终获得正确的值,因为您已经制作了该数据可用并将每个项目绑定到它。

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

class TreeViewItemViewModel : INotifyPropertyChanged
{
    bool IsExpanded { get; set; }
    bool IsSelected { get; set; }
    TreeViewItemViewModel Parent { get; }
    ObservableCollection<TreeViewItemViewModel> Children { get; }
}

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

于 2013-09-22T19:36:07.327 回答