WPF TreeView Virtualization

2020-07-02 06:07发布

问题:

I'm trying to figure out this virtualization feature, I'm not sure if I'm understanding it wrong or what's going on, but I'm using the ANTS memory profiler to check the number of items in a virtualized TreeView, and it just keeps increasing. I have a TreeView with 1,001 items (1 root, 1000 sub-items), and I always get up to 1,001 TreeViewItems, 1,001 ToggleButtons and 1,001 TextBlocks. Isn't virtualization supposed to re-use the items? If so, why would I have 1,001 of each? Also, the CleanUpVirtualizedItem never fires.

Let me know if I'm understanding this wrong and if you have resources on how to use this. I've searched over the internet but haven't found anything useful.

EDIT:

Even the memory used by the tree grows from aporx. 4mb to 12mb when I expand and scroll through all the items.

Let me know thanks.

This is my code.

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)
        {

        }
    }

回答1:

The difference is UI virtualization (which WPF supports out of the box on varying controls) versus data virtualization (which WPF does not support out of the box).

It boils down to UI virtualization only rendering what is needed and within view; while data virtulization only holding what may be needed at a given time in memory.

Bea has two great posts about UI virtualization and data virtualization and goes into the differences and how to workaround the limitation of no support for data virtualization which appears to be what you are after.

EDIT:

As of 3.5 SP1 support for virtualization was added to the TreeView. Perhaps removing your ItemsPanel template and just setting the properties on the TreeView should suffice.



回答2:

Ok, the problem is that virtualization only works when the TreeView is using Binding, and not when the nodes are generated one by one in the code like my example. What a bummer.



回答3:

Thats not accurate. True that virtualuzation only works with binding, however, as I observed in some sample application is that recycling of elements occur only on the root items of the treeview.

so if you have only 1 root item with 1000 children, no recycling will occur because theres only 1 container available for recycling.

if you have 100 root items, and each of them has 100 children, you will get partial recycling, because only the root 100 items will be recycled, but other 9900 child items will be stored in memory.

of course the problem gets only worse if your tree nesting level is greater than 2 or 3.

I dont know if theres a solution to this problem.