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

Разработка приложения 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, вы избегаете инициирования ненужных вычислений разметки.

Построение дерева сверху вниз

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

См. также