优化性能:布局和设计

WPF 应用程序的设计可以通过在计算布局和验证对象引用时产生不必要的开销来影响其性能。 对象的构造(尤其是在运行时)可能会影响应用程序的性能特征。

本主题在这些方面提供性能建议。

布局

术语“布局传递”描述了测量和排列 Panel 派生对象的子集合成员,并在屏幕上绘制它们的过程。 布局处理是一个数学密集型过程——集合中的子元素数量越大,所需进行的计算也就越多。 例如,每次集合中的子 UIElement 对象更改其位置时,它都有可能触发布局系统的新传递。 由于对象特征与布局行为之间存在密切的关系,因此必须了解可以调用布局系统的事件类型。 通过尽量减少布局过程的无用调用,你的应用程序将性能更佳。

布局系统为集合中的每个子成员完成两个阶段:测量阶段和排列阶段。 每个子对象通过其重写后的MeasureArrange方法实现自身特定的布局行为。 在最简单的情况下,布局是一个递归系统,驱动元素在屏幕上进行大小调整、定位和绘制。

如果发生以下任一操作,则会再次调用布局传递过程:

  • 子对象将添加到集合中。

  • A LayoutTransform 应用于子对象。

  • UpdateLayout 子对象调用该方法。

  • 当依赖属性的值发生更改,并且该属性被标记为具有影响测量或排列过程的元数据时。

尽可能使用最有效的面板

布局过程的复杂性直接基于所使用的派生元素的 Panel布局行为。 例如, GridStackPanel 控件提供的功能比 Canvas 控件多得多。 这一功能增加的价格是性能成本的提高。 但是,如果你不需要控件提供的功能 Grid ,则应使用成本较低的替代项,例如 Canvas 或自定义面板。

有关详细信息,请参阅 面板概述

更新而不是替换 RenderTransform

你也许能够更新 Transform 而不是将它替换为 RenderTransform 属性的值。 这在涉及动画的方案中尤其如此。 通过更新现有的Transform,可以避免启动不必要的布局计算。

构建你的树 Top-Down

在逻辑树中添加或删除某个节点时,将引发节点的父级及其所有子级的属性失效。 因此,应始终遵循自上而下构造模式,以避免已验证的节点上不必要的失效成本。 下表显示了从上到下构建树与从下到上构建树之间的执行速度差异,其中树深度为 150 个级别,每个级别都有一个 TextBlockDockPanel

行动 树构建 (以 ms 为单位) 呈现 - 包括树构建(以 ms 为单位)
自下而上 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;
    }
}
Private Sub OnBuildTreeTopDown(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim textBlock As New TextBlock()
    textBlock.Text = "Default"

    Dim parentPanel As New DockPanel()
    Dim childPanel As DockPanel

    myCanvas.Children.Add(parentPanel)
    myCanvas.Children.Add(textBlock)

    For i As Integer = 0 To 149
        textBlock = New TextBlock()
        textBlock.Text = "Default"
        parentPanel.Children.Add(textBlock)

        childPanel = New DockPanel()
        parentPanel.Children.Add(childPanel)
        parentPanel = childPanel
    Next i
End Sub

有关逻辑树的详细信息,请参阅 WPF中的 树。

另请参阅