Поделиться через


Оптимизация производительности: макет и проектирование

Проектирование приложения WPF может повлиять на производительность, создавая ненужные издержки при вычислении макета и проверке ссылок на объекты. Создание объектов, особенно во время выполнения, может повлиять на характеристики производительности приложения.

В этом разделе приведены рекомендации по производительности в этих областях.

Схема

Термин "компоновочный проход" описывает процесс измерения и упорядочения элементов коллекции объектов, производных от Panel, а затем их отрисовка на экране. Процесс прохождения макета включает интенсивные математические расчёты — чем больше количество элементов в коллекции, тем больше вычислений требуется. Например, каждый раз, когда дочерний объект UIElement в коллекции меняет своё положение, он может вызвать новый цикл обработки системой макета. Из-за тесной связи между характеристиками объекта и поведением макета важно понимать тип событий, которые могут вызывать систему макета. Приложение будет работать лучше, если максимально сократить количество ненужных вызовов прохода макета.

Система макета совершает два прохода для каждого дочернего элемента в коллекции: измерение и размещение. Каждый дочерний объект предоставляет собственную переопределенную реализацию методов Measure и Arrange, чтобы обеспечить свое конкретное макетное поведение. В своей самой простой форме макет представляет собой рекурсивную систему, которая приводит к тому, что элемент измеряется, позиционируется и отображается на экране.

  • Дочерний объект UIElement начинает процесс размещения, сначала измеряя свои основные свойства.

  • Свойства объекта FrameworkElement, связанные с размером, такие как Width, Heightи Margin, вычисляются.

  • Применяется логика Panel, например, свойство DockDockPanelили свойство OrientationStackPanel.

  • Содержимое упорядочено или размещено после измерения всех дочерних объектов.

  • Коллекция дочерних объектов отображается на экране.

Процесс передачи макета вызывается снова, если выполняются какие-либо из следующих действий:

  • Дочерний объект добавляется в коллекцию.

  • К дочернему объекту применяется LayoutTransform.

  • Метод UpdateLayout вызывается для дочернего объекта.

  • При изменении значения свойств зависимости, помеченных метаданными, влияющими на измерение или расположение проходов.

Использование наиболее эффективной панели, где это возможно

Сложность процесса макета непосредственно зависит от характеристик макета элементов, производных от Panel, которые вы используете. Например, элемент управления Grid или StackPanel предоставляет гораздо больше возможностей, чем элемент управления Canvas. Цена на это увеличение функциональных возможностей является более большим увеличением затрат на производительность. Однако если вам не требуются функциональные возможности, которые предоставляет элемент управления Grid, следует использовать менее дорогостоящие варианты, например Canvas или настраиваемую панель.

Дополнительные сведения см. в разделе Обзор панелей.

Обновите, а не заменяйте RenderTransform

Вы можете обновить Transform, а не заменить его значением свойства RenderTransform. Это особенно верно в сценариях, связанных с анимацией. Обновив существующий Transform, вы избегаете инициирования ненужного расчета макета.

Постройте дерево Top-Down

При добавлении или удалении узла из логического дерева создаются недопустимые значения свойств на родительском узле и всех его дочерних элементах. Таким образом, всегда следует придерживаться структуры построения от верхнего уровня к нижнему, чтобы избежать излишних затрат на аннулирование верифицированных узлов. В следующей таблице показана разница в скорости выполнения между построением дерева сверху вниз и снизу вверх, где у дерева 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;
    }
}
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.

См. также