Otimizando desempenho: layout and design

O design do aplicativo WPF pode afetar seu desempenho criando sobrecarga desnecessária no cálculo do layout e validando referências de objeto. A construção de objetos, particularmente no tempo de execução, pode afetar as características de desempenho do seu aplicativo.

Este tópico apresenta recomendações de desempenho nessas áreas.

Layout

O termo "passe de layout" descreve o processo de medir e organizar os membros da coleção de crianças de um Panelobjeto derivado e, em seguida, desenhá-los na tela. O cálculo de layout é um processo matematicamente intensivo: quanto maior o número de filhos na coleção, maior será o número de cálculos necessários. Por exemplo, cada vez que um objeto filho UIElement na coleção muda de posição, ele tem o potencial de disparar uma nova passagem pelo sistema de layout. Devido ao forte relacionamento entre as características de objeto e comportamento de layout, é importante compreender os tipos de eventos que podem invocar o sistema de layout. Seu aplicativo terá um desempenho melhor reduzindo ao máximo as invocações desnecessárias do cálculo de layout.

O sistema de layout completa dois cálculos para cada membro filho em uma coleção: um cálculo de medição e um cálculo de organização. Cada objeto filho fornece sua própria implementação substituída dos Measure métodos e Arrange para fornecer seu próprio comportamento de layout específico. Em sua forma mais simples, o layout é um sistema recursivo que leva a um elemento a ser dimensionado, posicionado e desenhado na tela.

  • Um objeto filho UIElement inicia o processo de layout primeiro tendo suas propriedades principais medidas.

  • As propriedades do FrameworkElement objeto relacionadas ao tamanho, como Width, e Margin, Heightsão avaliadas.

  • Panel-lógica específica é aplicada, como a DockDockPanelpropriedade do , ou a Orientation propriedade do StackPanel.

  • O conteúdo é organizado, ou posicionado, após a medição de todos os objetos filho.

  • A coleção de objetos filho é desenhada na tela.

O processo de cálculo de layout será invocado novamente se qualquer uma das ações a seguir ocorrer:

  • Um objeto filho é adicionado à coleção.

  • A LayoutTransform é aplicado ao objeto filho.

  • O UpdateLayout método é chamado para o objeto filho.

  • Quando ocorre uma alteração ao valor da propriedade de dependência marcada com metadados que afetam a medida ou cálculos da organização.

Usar o painel mais eficiente quando possível

A complexidade do processo de layout é diretamente baseada no comportamento do layout dos elementos derivados que Panelvocê usa. Por exemplo, um controle ou StackPanel fornece muito mais funcionalidade do que um GridCanvas controle. O preço para esse aumento de funcionalidade é um aumento maior nos custos de desempenho. No entanto, se você não precisar da funcionalidade que um controle fornece, você deve usar as alternativas menos dispendiosas, como um ou um GridCanvas painel personalizado.

Para obter mais informações, consulte Visão geral dos painéis.

Atualizar, em vez de substituir, uma RenderTransform

Você pode atualizar um Transform em vez de substituí-lo como o valor de uma RenderTransform propriedade. Isso é especialmente verdadeiro em cenários que envolvem animação. Ao atualizar um , você evita iniciar um Transformcálculo de layout desnecessário.

Compilar sua árvore de cima para baixo

Quando um nó é adicionado ou removido da árvore lógica, invalidações de propriedade são geradas no pai do nó e todos os seus filhos. Como resultado, um padrão de construção de cima para baixo deve sempre ser seguido para evitar o custo de invalidações desnecessárias em nós que já foram validados. A tabela a seguir mostra a diferença na velocidade de execução entre a construção de uma árvore de cima para baixo versus de baixo para cima, onde a árvore tem 150 níveis de profundidade com um único TextBlock e DockPanel em cada nível.

Ação Build da árvore (em ms) Renderizar – inclui o build da árvore (em ms)
De baixo para cima 366 454
De cima para baixo 11 96

O exemplo de código a seguir demonstra como criar uma árvore de cima para baixo.

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

Para obter mais informações sobre a árvore lógica, consulte Árvores no WPF.

Confira também