我一直在检查WPF的TreeView控件的UI虚拟化功能,据我所知,自.NET 3.5 SP1起可用.
我做了一个简单的项目,以确保UI虚拟化正确执行,并发现它根本不起作用 – 所有项目都被检索,而不仅仅是当前显示在屏幕上的项目.
我的XAML看起来像这样
<TreeView x:Name="myTree" Height="150" ItemsSource="{Binding Items}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
ScrollViewer.IsDeferredScrollingEnabled="True" />
而我的代码背后
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;
}
请注意,MyList是我自己的IList实现,它包含一个ArrayList,除了转发到保持的ArrayList并向控制台写入调用哪个方法/属性之外什么也没做.例如:
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;
}
}
如果我用ListBox替换我的TreeView,UI虚拟化按预期工作 – 即只需要约20个项目而不是整个1000.
我在这里做错了吗?
编辑
我也尝试将默认的ItemsPanel替换为VirtualizingStackPanel,但是我得到了相同的结果.
解决方法:
TreeView的默认ItemsPanelTemplate是StackPanel而不是VirtualizingStackPanel,这就是为什么你看不到虚拟化的原因.而对于ListBox,默认的ItemsPanelTemplate是VirtualizingStackPanel,这就是为什么设置VirtualizingStackPanel.IsVirtualizing =“True”适用于ListBox的原因.
要在TreeView上启用虚拟化,除了设置属性VirtualizingStackPanel.IsVirtualizing =“True”,您需要覆盖其默认的itemsPanelTemplate,如下所示 –
<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>