首页 > 代码库 > WPF Virtualization

WPF Virtualization

WPF虚拟化技术分为UI 虚拟化和数据虚拟化

第一种方法被称为"UI 虚拟化"。支持虚拟化用户界面的控件是足够聪明来创建只显示的是实际在屏幕上可见的数据项目所需的 UI 元素。例如,假设我们有一个滚动的列表框是绑定到 1,000,000 项目的数据,但在任何时候是可见的只有 100。没有 UI 虚拟化,列表框将创建 100 万 ListBoxItems — — 一个缓慢的过程 — — 并包括他们在 UI 中,即使只有一百人是可见。与用户界面虚拟化,另一方面,列表框中将只创建 100 ListBoxItems (或更多,从而提高滚动性能)。

第二种方法,被称为"虚拟化的数据,"更进了一步。使用数据虚拟化的控件不会加载到内存的所有数据项。相反,它只加载显示所需的。在我们上面的列表框示例,使用数据的虚拟化解决方案将只保留约 100 个数据项目在内存中在任何给定时间。

VirtualizingStackPanel.IsVirtualizing 附加属性

 

VirtualizingStackPanel.VirtualizationMode 附加属性


默认情况下, VirtualizingStackPanel 创建每个可见项的项容器以及丢弃,当不再需要时 (例如,当项滚动到视图之外时)。  ItemsControl 包含许多项目时,会创建并放弃项容器处理会对性能产生负面影响。  VirtualizingStackPanel.VirtualizationMode 设置为 Recycling时, VirtualizingStackPanel 重用项目容器而不是每次创建新的。
 1 <StackPanel> 2  3   <StackPanel.Resources> 4     <src:LotsOfItems x:Key="data"/> 5   </StackPanel.Resources> 6  7   <ListBox Height="150" ItemsSource="{StaticResource data}"  8              VirtualizingStackPanel.VirtualizationMode="Recycling" /> 9 10 </StackPanel>

 

容器回收

.NET 3.5 SP1 支持 UI 容器的重用已经在内存中。例如,想象当加载一个列表框,则 30 ListBoxItems 创建要显示的可见数据。当用户滚动列表框,而不是丢弃滚动到视图之外的 ListBoxItems 和创建新的数据项的滚动到视图,WPF 会重用现有的 ListBoxItems。此结果中显著的性能改进与以前的版本相比,因为它减少了的时间花了初始化 ListBoxItems。因为垃圾回收不是瞬时的它也减少了 ListBoxItems 存储器中的数一次。

您可以启用容器回收通过在您的控件上设置附加的属性"VirtualizingStackPanel.VirtualizationMode"到"Recycling":

 1 <ListBox ScrollViewer.IsDeferredScrollingEnabled="True" … /> 

为了保持向后兼容与早期版本的行为,容器回收的默认被禁用的 (默认的 VirtualizationMode 是"Standard")。作为一个经验法则,我建议将此属性设置每次创建一个控件,需要滚动以显示数据的项目。

延迟滚动

"递延滚动"是一种功能,允许用户拖动滚动条滑块周围而无需更改显示的项,直到滚动条滑块被释放。这提高了应用程序的感知的响应滚动时显示的项使用复杂的模板,但当然,用户不能看到他们在滚动的项目。

与.NET 3.5 SP1 中,它有可能启用延迟滚动通过在控件上设置附加的属性:

 1 <ListBox ScrollViewer.IsDeferredScrollingEnabled="True" … /> 

 

分层数据

在.NET 3.5 SP1 中,WPF 团队扩展用户界面虚拟化到 TreeView 通过向 VirtualizingStackPanel 添加对分层数据的支持。因此,容器回收和上面讨论的递延滚动功能也适用于分层数据。默认情况下,在 TreeView 中禁用用户界面虚拟化 — — 在这里是如何启用它:

 1 <TreeView VirtualizingStackPanel.IsVirtualizing="True" 

这个属性是非常有用的不只是为树视图,但对于任何控件的使用 VirtualizingStackPanel 和那不设置 IsVirtualizing 为 true (例如 ItemsControl)。列表框中已经将 IsVirtualizing 设置为 True,默认情况下,这样就无需显式设置它。

局限性

.NET 3.5 SP1 固定很多以前的限制在 UI 虚拟化,但仍然是一对夫妇仍然:

  • ScrollViewer 目前允许两种滚动模式: 平滑滚动的像素 (CanContentScroll = false) 或离散按项目滚动 (CanContentScroll = true)。目前 WPF 支持用户界面虚拟化,只有当按项目滚动。基于像素的滚动也被称为"物理滚动"和基于项目的滚动也被称为"逻辑滚动"。
  • 使用数据绑定"分组"功能时,那里是没有用户界面虚拟化的支持。

这些真的是相同的限制。如果你看看默认的样式列表框、 列表视图和组合框,你会发现下面的触发器:

1 <Trigger Property="IsGrouping" Value=http://www.mamicode.com/"true">2  <Setter Property="ScrollViewer.CanContentScroll" Value=http://www.mamicode.com/"false"/>3 </Trigger>

分组执行假定每个组是一个单独的项目中包含它的 ItemsControl。因为每个组可以 (并且通常所做的) 有很多子项目,按项目滚动将结果真的不好的用户体验 — — 滚动下来有点会导致一大跳下一组的顶部。这就是为什么团队决定切换到基于像素滚动显示分组数据时。不幸的后果是没有用户界面虚拟化支持的分组时。

WPF Virtualization