【问题标题】:WPF TreeView VirtualizationWPF 树视图虚拟化
【发布时间】:2010-12-28 20:21:17
【问题描述】:

我正在尝试弄清楚这个虚拟化功能,我不确定我是否理解错了或者发生了什么,但我正在使用 ANTS 内存分析器来检查虚拟化 TreeView 中的项目数,而且还在不断增加。我有一个包含 1,001 个项目(1 个根、1000 个子项目)的 TreeView,而且我总是得到多达 1,001 个 TreeViewItems、1,001 个 ToggleButtons 和 1,001 个 TextBlocks。虚拟化不应该重复使用这些项目吗?如果是这样,为什么我每个都有 1,001 个?此外,CleanUpVirtualizedItem 永远不会触发。

如果我理解错了,以及您是否有关于如何使用它的资源,请告诉我。我在互联网上搜索过,但没有找到任何有用的东西。

编辑:

甚至树使用的内存也是从 aporx 增长而来的。展开并滚动浏览所有项目时为 4mb 到 12mb。

告诉我谢谢。

这是我的代码。

XAML:

<Window x:Class="RadTreeViewExpandedProblem.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <TreeView x:Name="treeView"
                  VirtualizingStackPanel.IsVirtualizing="True"
                  VirtualizingStackPanel.CleanUpVirtualizedItem="TreeView_CleanUpVirtualizedItem">
            <TreeView.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel />
                </ItemsPanelTemplate>
            </TreeView.ItemsPanel>
        </TreeView>
    </Grid>
</Window>

C#:

 public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            TreeViewItem rootItem = new TreeViewItem() { Header = "Item Level 0" };

            for (int i = 0; i < 1000; i++)
            {
                TreeViewItem itemLevel1 = new TreeViewItem() { Header = "Item Level 1" };

                itemLevel1.Items.Add(new TreeViewItem());

                rootItem.Items.Add(itemLevel1);
            }

            treeView.Items.Add(rootItem);
        }

        private void TreeView_CleanUpVirtualizedItem(object sender, CleanUpVirtualizedItemEventArgs e)
        {

        }
    }

【问题讨论】:

    标签: wpf virtualization


    【解决方案1】:

    区别在于 UI 虚拟化(WPF 开箱即用地支持各种控件)与数据虚拟化(WPF 不支持开箱即用)。

    它归结为 UI 虚拟化只呈现需要的内容和视图;而数据虚拟化仅在内存中保存给定时间可能需要的内容。

    Bea 有两篇关于 UI virtualizationdata virtualization 的精彩帖子,并深入探讨了差异以及如何解决不支持数据虚拟化的限制,这似乎是您所追求的。

    编辑:

    从 3.5 SP1 开始,TreeView 中添加了对虚拟化的支持。也许删除您的 ItemsPanel 模板并仅在 TreeView 上设置属性就足够了。

    【讨论】:

    • 我明白这一点。在我的问题中,我说的是 UI 虚拟化,这就是为什么我不明白为什么它为 10001 项中的每一项创建一个容器,尽管虚拟化设置为 true。
    • @Carlos 添加了有关删除 ItemsPanel 模板的说明;因为我相信从 3.5 SP1 开始的默认模板应该是 VirtualizingStackPanel,所以不需要更改模板,只需像通过 TreeView 一样启用该属性即可。
    • 尝试了您在编辑中提到的内容。也没有用。我仍然每个控件都有一千个。这真的很奇怪。而且 CleanUpVirtualizedItem 事件仍然没有被触发,这是虚拟化不起作用的另一个线索。
    • @Carlos 没有隐藏样式被应用?你已经把它缩小到上面的代码了吗?另一件要尝试的事情是通过 DataBound 数据而不是显式添加一个...
    • 好的,我明白了。虚拟化仅适用于 Binding……真是太糟糕了。
    【解决方案2】:

    好的,问题是虚拟化仅在 TreeView 使用 Binding 时有效,而不是像我的示例那样在代码中一一生成节点时有效。真可惜。

    【讨论】:

    • 这应该不是太大的障碍,只需使用 ObservableCollection 将树视图绑定到并在需要时将您的项目添加到集合中 - 这是更惯用的 WPF 方式,您不需要想直接手动添加项目。
    • 我喜欢你的想法。我知道何时需要更多项目的方法是在树上向上或向下滚动。您认为这种方法可行吗?
    【解决方案3】:

    那不准确。确实,虚拟化仅适用于绑定,但是,正如我在一些示例应用程序中观察到的那样,元素的回收仅发生在树视图的根项上。

    因此,如果您只有 1 个根项和 1000 个子项,则不会发生回收,因为只有 1 个容器可供回收。

    如果你有 100 个根项,每个项有 100 个子项,你将获得部分回收,因为只有根 100 个项会被回收,而其他 9900 个子项将存储在内存中。

    当然,如果您的树嵌套级别大于 2 或 3,问题只会变得更糟。

    不知道有没有办法解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2013-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多