优化性能:布局和设计
更新:2007 年 11 月
WPF 应用程序的设计在计算布局和验证对象引用时会产生不必要的系统开销,从而影响到性能。对象的构造会影响到应用程序的性能特征,在运行时更是如此。
本主题提供这些方面的性能改进建议。
Layout
“布局处理过程”一词指测量和排列 Panel 派生对象的子级集合的成员,然后在屏幕绘制它们的过程。布局处理过程是一个数学密集型过程,即:集合中的子级数目越多,所需的计算量就越大。例如,每当集合中的一个子 UIElement 对象改变其位置时,布局系统就有可能触发一个新的处理过程。由于对象特征与布局行为之间的关系非常紧密,因此必须了解可以调用布局系统的事件类型。应用程序应尽可能减少不必要的布局处理过程调用,从而改善性能。
布局系统对集合中的每个子成员都完成两个处理过程:测量处理过程和排列处理过程。每个子对象都针对 Measure 和 Arrange 方法提供它自己的重写实现,以提供其特定的布局行为。简单地说,布局是一个递归系统,实现在屏幕上对元素进行大小调整、定位和绘制。
子 UIElement 对象通过首先测量它的核心属性来开始布局过程。
计算与大小相关的、对象的 FrameworkElement 属性,如 Width、Height 和 Margin。
应用特定于 Panel 的逻辑,如 DockPanel 的 Dock 属性,或者 StackPanel 的 Orientation 属性。
在测量所有子对象后,将排列或定位内容。
将子对象集合绘制到屏幕上。
如果发生下列任意操作,将再次调用布局处理过程:
向集合中添加了一个子对象。
向子对象应用了 LayoutTransform。
为子对象调用了 UpdateLayout 方法。
用影响测量或排列过程的元数据进行了标记的依赖项属性的值发生更改。
尽可能使用最有效的面板
布局过程的复杂性直接取决于您使用的 Panel 派生元素的布局行为。例如,Grid 或 StackPanel 控件提供的功能比 Canvas 控件多很多。功能大大提高的代价是性能成本也大大提高。但是,如果您不需要 Grid 控件提供的功能,则应使用成本较低的其他控件,如 Canvas 或自定义面板。
有关更多信息,请参见面板概述。
更新而不替换 RenderTransform
您可以更新 Transform,而不是将它作为 RenderTransform 属性的值来替换。当涉及动画时,此方法尤其有用。通过更新现有的 Transform,可以避免启动不必要的布局计算。
从上到下生成树
当在逻辑树中添加或移除节点时,会在该节点的父级及其所有子级上引起属性失效。因此,应始终遵循从上到下的构造模式,以避免因为在经过验证的节点中出现不必要的失效而为此付出代价。下表从执行速度的角度列出了从上到下构建树与从下到上构建树之间的区别,其中树有 150 级深,并且每一级都有一个 TextBlock 和 DockPanel。
操作 |
构建树(以毫秒为单位) |
呈现 — 包括生成树(以毫秒为单位) |
---|---|---|
从下到上 |
366 |
454 |
从上到下 |
11 |
96 |
下面的代码示例演示如何从上到下创建树。
private void OnBuildTreeTopDown(object sender, RoutedEventArgs e)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "Default";
DockPanel parentPanel = new DockPanel();
DockPanel childPanel;
myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);
for (int i = 0; i < 150; i++)
{
textBlock = new TextBlock();
textBlock.Text = "Default";
parentPanel.Children.Add(textBlock);
childPanel = new DockPanel();
parentPanel.Children.Add(childPanel);
parentPanel = childPanel;
}
}
有关逻辑树的更多信息,请参见 WPF 中的树。