优化性能:控件
Windows Presentation Foundation (WPF) 包含大多数 Windows 应用程序中使用的许多常见用户界面 (UI) 组件。 本主题包含提高 UI 性能的技术。
显示大型数据集
ListView 和 ComboBox 等 WPF 控件用于显示应用程序中的项列表。 如果要显示的列表较大,则应用程序性能可能受到影响。 这是因为标准布局系统会为每个与列表控件关联的项创建布局容器,并计算其布局大小和位置。 通常,无需同时显示所有项,而是显示子集,然后用户滚动浏览列表。 这种情况下,使用 UI 虚拟化具有意义,这意味着生成项容器,且项的关联布局计算会推迟,直到项可见时。
UI 虚拟化是列表控件的一个重要方面。 不应混淆 UI 虚拟化和数据虚拟化。 UI 虚拟化在内存中仅存储可见项,但在数据绑定方案中会存储内存中的整个数据结构。 相反,数据虚拟化仅存储内存中屏幕上可见的数据项。
默认情况下,对于 ListView 和 ListBox 控件,在其列表项绑定到数据时会启用 UI 虚拟化。 通过将 VirtualizingStackPanel.IsVirtualizing 附加属性设置为 true
可启用 TreeView 虚拟化。 若要对派生自 ItemsControl 的自定义控件或使用 StackPanel 类的现有控件(例如 ComboBox)启用 UI 虚拟化,可将 ItemsPanel 设置为 VirtualizingStackPanel,并将 IsVirtualizing 设置为 true
。 遗憾的是,可对没有实现虚拟化的控件禁用 UI 虚拟化。 以下为禁用 UI 虚拟化的条件列表。
项容器直接添加到 ItemsControl。 例如,如果应用程序显式将 ListBoxItem 对象添加到 ListBox,则 ListBox 不会虚拟化 ListBoxItem 对象。
ItemsControl 中的项容器类型不同。 例如,使用 Separator 对象的 Menu 无法实现项回收,其原因在于 Menu 包含 Separator 和 MenuItem 类型的对象。
将 CanContentScroll 设置为
false
。将 IsVirtualizing 设置为
false
。
虚拟化项容器时需要考虑到一个重要因素,即是否具有与属于项的项容器相关联的其他状态信息。 这种情况下,必须保存其他状态。 例如,你可能具有 Expander 控件中所含的一个项,且 IsExpanded 状态绑定到项的容器而非项自身。 对新项重复使用此容器时,IsExpanded 的当前值会用于新项。 此外,旧项会丢失正确的 IsExpanded 值。
当前,无任何 WPF 控件提供对数据虚拟化的内置支持。
容器回收
对继承自 ItemsControl 的控件而言,.NET Framework 3.5 SP1 中增添的 UI 虚拟化优化是容器回收,此优化还可提高滚动性能。 使用 UI 虚拟化的 ItemsControl 在填充时,会为每个滚动到视图的项创建项容器并销毁每个滚动到视图外的项的项容器。 容器回收可使控件对不同的数据项重复使用现有项容器,从而在用户滚动 ItemsControl 时不会不断创建和销毁项容器。 通过将 VirtualizationMode 附加属性设置为 Recycling,可选择启用项回收。
任何支持虚拟化的 ItemsControl 皆可使用容器回收。 有关如何在 ListBox 上启用容器回收的示例,请参阅提高 ListBox 的滚动性能。
支持双向虚拟化
VirtualizingStackPanel 提供内置的单向(水平或垂直)UI 虚拟化支持。 若要对控件使用双向虚拟化,必须实现一个扩展 VirtualizingStackPanel 类的自定义面板。 VirtualizingStackPanel 类公开一些虚拟方法,例如 OnViewportSizeChanged、LineUp、PageUp 和 MouseWheelUp。通过这些虚拟方法可检测列表可见部分中的更改并相应进行处理。
优化模板
可视化树包含应用程序中所有可视元素。 除直接创建的对象外,它还包括由于模板扩展而产生的对象。 例如,创建 Button 时,也会获取可视化树中的 ClassicBorderDecorator 和 ContentPresenter 对象。 如果尚未优化模板控件,则要在可视化树中创建大量不必要的额外对象。 有关可视化树的详细信息,请参见 WPF 图形呈现概述。
延迟滚动
默认情况下,用户拖动滚动条上的滚动块时,内容视图会不断更新。 如果控件中滚动较慢,请考虑使用延迟滚动。 在延迟滚动中,仅在用户释放滚动块时才会更新内容。
若要实现延迟滚动,请将 IsDeferredScrollingEnabled 属性设置为 true
。 IsDeferredScrollingEnabled 为附加属性,可在 ScrollViewer 以及其控件模板中具有 ScrollViewer 的任何控件上进行设置。
实现性能功能的控件
下表列出了显示数据的常见控件及其性能功能支持。 有关如何启用这些功能的信息,请参阅先前章节。
控件 | Virtualization | 容器回收 | 延迟滚动 |
---|---|---|---|
ComboBox | 可启用 | 可启用 | 可启用 |
ContextMenu | 可启用 | 可启用 | 可启用 |
DocumentViewer | 不可用 | 不可用 | 可启用 |
ListBox | 默认值 | 可启用 | 可启用 |
ListView | 默认值 | 可启用 | 可启用 |
TreeView | 可启用 | 可启用 | 可启用 |
ToolBar | 不可用 | 不可用 | 可启用 |
注意
有关如何在 TreeView 上启用虚拟化和容器回收的示例,请参阅提高 TreeView 的性能。