Edit

Share via


Optimizing Performance: Layout and Design

The design of your WPF application can impact its performance by creating unnecessary overhead in calculating layout and validating object references. The construction of objects, particularly at run time, can affect the performance characteristics of your application.

This topic provides performance recommendations in these areas.

Layout

The term "layout pass" describes the process of measuring and arranging the members of a Panel-derived object's collection of children, and then drawing them onscreen. The layout pass is a mathematically-intensive process—the larger the number of children in the collection, the greater the number of calculations required. For example, each time a child UIElement object in the collection changes its position, it has the potential to trigger a new pass by the layout system. Because of the close relationship between object characteristics and layout behavior, it's important to understand the type of events that can invoke the layout system. Your application will perform better by reducing as much as possible any unnecessary invocations of the layout pass.

The layout system completes two passes for each child member in a collection: a measure pass, and an arrange pass. Each child object provides its own overridden implementation of the Measure and Arrange methods in order to provide its own specific layout behavior. At its simplest, layout is a recursive system that leads to an element being sized, positioned, and drawn onscreen.

  • A child UIElement object begins the layout process by first having its core properties measured.

  • The object's FrameworkElement properties that are related to size, such as Width, Height, and Margin, are evaluated.

  • Panel-specific logic is applied, such as the Dock property of the DockPanel, or the Orientation property of the StackPanel.

  • Content is arranged, or positioned, after all child objects have been measured.

  • The collection of child objects is drawn to the screen.

The layout pass process is invoked again if any of the following actions occur:

  • A child object is added to the collection.

  • A LayoutTransform is applied to the child object.

  • The UpdateLayout method is called for the child object.

  • When a change occurs to the value of a dependency property that is marked with metadata affecting the measure or arrange passes.

Use the Most Efficient Panel where Possible

The complexity of the layout process is directly based on the layout behavior of the Panel-derived elements you use. For example, a Grid or StackPanel control provides much more functionality than a Canvas control. The price for this greater increase in functionality is a greater increase in performance costs. However, if you do not require the functionality that a Grid control provides, you should use the less costly alternatives, such as a Canvas or a custom panel.

For more information, see Panels Overview.

Update Rather than Replace a RenderTransform

You may be able to update a Transform rather than replacing it as the value of a RenderTransform property. This is particularly true in scenarios that involve animation. By updating an existing Transform, you avoid initiating an unnecessary layout calculation.

Build Your Tree Top-Down

When a node is added or removed from the logical tree, property invalidations are raised on the node's parent and all its children. As a result, a top-down construction pattern should always be followed to avoid the cost of unnecessary invalidations on nodes that have already been validated. The following table shows the difference in execution speed between building a tree top-down versus bottom-up, where the tree is 150 levels deep with a single TextBlock and DockPanel at each level.

Action Tree building (in ms) Render—includes tree building (in ms)
Bottom-up 366 454
Top-down 11 96

The following code example demonstrates how to create a tree top down.

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

For more information on the logical tree, see Trees in WPF.

See also