I've been checking out the UI virtualization feature for WPF's TreeView control, which as I understand, is available since .NET 3.5 SP1.
I made a simple project to make sure that UI virtualization is performed correctly, and found out that it doesn't work at all - all of the items are retrieved rather than just the ones currently displayed on the screen.
My XAML looks like this
<TreeView x:Name="myTree" Height="150" ItemsSource="{Binding Items}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
ScrollViewer.IsDeferredScrollingEnabled="True" />
And my code behind
public IEnumerable Items { get; set; }
public MainWindow()
{
Items = GenerateList();
this.DataContext = this;
InitializeComponent();
}
private IEnumerable GenerateList()
{
MyList list = new MyList();
for (int i = 0; i < 1000; i++)
{
list.Add("Item " + i);
}
return list;
}
Note that MyList
is my own implementation of IList
that holds an ArrayList
and does nothing more than forward calls to the held ArrayList
and write to the console which method/property was called. For example:
public object this[int index]
{
get
{
Debug.WriteLine(string.Format("get[{0}]", index));
return _list[index];
}
set
{
Debug.WriteLine(string.Format("set[{0}]", index));
_list[index] = value;
}
}
If I replace my TreeView with a ListBox, UI virtualization works as expected - i.e. only ~20 items are requested and not the whole 1000.
Am I doing something wrong here?
EDIT
I've also tried replacing the default ItemsPanel
to VirtualizingStackPanel
, as suggested , but I'm getting the same results.
Default ItemsPanelTemplate
for TreeView is StackPanel
and not VirtualizingStackPanel
that's why you can't see virtualization in it. Whereas for ListBox default ItemsPanelTemplate is VirtualizingStackPanel that's why setting VirtualizingStackPanel.IsVirtualizing="True"
works for ListBox.
To enable virtualization on your TreeView apart from setting property VirtualizingStackPanel.IsVirtualizing="True"
, you need to override the its default itemsPanelTemplate like this -
<TreeView x:Name="myTree" Height="150" ItemsSource="{Binding Items}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
VirtualizingStackPanel.CleanUpVirtualizedItem="myTree_CleanUpVirtualizedItem"
ScrollViewer.IsDeferredScrollingEnabled="True">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
</TreeView>