Compartilhar via


Otimizar seu layout XAML

APIs importantes

  • Painel

Layout é o processo de definição da estrutura visual para sua interface do usuário. O mecanismo principal para descrever o layout em XAML é por meio de painéis, que são objetos de contêiner que permitem posicionar e organizar os elementos da interface do usuário dentro deles. O layout pode ser uma parte cara de um aplicativo XAML, tanto no uso da CPU quanto na sobrecarga de memória. Aqui estão algumas etapas simples que você pode executar para melhorar o desempenho de layout do seu aplicativo XAML.

Reduzir estrutura de layout

O maior ganho no desempenho de layout vem da simplificação da estrutura hierárquica da árvore de elementos da interface do usuário. Os painéis existem na árvore visual, mas são elementos estruturais, não elementos que produzem pixels como um botão ou um retângulo . Simplificar a árvore reduzindo o número de elementos que não produzem pixels normalmente fornece um aumento de desempenho significativo.

Muitas interfaces do usuário são implementadas com painéis encaixados, o que resulta em árvores profundas e complexas de painéis e elementos. É conveniente aninhar painéis, mas em muitos casos a mesma interface do usuário pode ser obtida com um painel único mais complexo. O uso de um único painel fornece melhor desempenho.

Quando reduzir a estrutura de layout

A redução da estrutura de layout de maneira trivial, por exemplo, removendo um painel aninhado da página de nível superior, não tem um efeito perceptível.

Os maiores ganhos de desempenho vêm da redução da estrutura de layout repetida na interface do usuário, como em um ListView ou GridView. Esses elementos ItemsControl usam um DataTemplate, que define uma subárvore de elementos da interface do usuário que são instanciados muitas vezes. Quando a mesma subárvore está sendo duplicada muitas vezes em seu aplicativo, qualquer melhoria no desempenho dessa subárvore tem um efeito multiplicativo sobre o desempenho geral do seu aplicativo.

Exemplos

Considere a interface do usuário a seguir.

Exemplo de layout de formulário

Esses exemplos mostram três maneiras de implementar a mesma interface do usuário. Cada escolha de implementação resulta em pixels quase idênticos na tela, mas difere substancialmente nos detalhes da implementação.

Opção1: elementos aninhados no StackPanel

Embora este seja o modelo mais simples, ele usa 5 elementos de painel e resulta em sobrecarga significativa.

  <StackPanel>
  <TextBlock Text="Options:" />
  <StackPanel Orientation="Horizontal">
      <CheckBox Content="Power User" />
      <CheckBox Content="Admin" Margin="20,0,0,0" />
  </StackPanel>
  <TextBlock Text="Basic information:" />
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Name:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Email:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Password:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <Button Content="Save" />
</StackPanel>

Opção 2: uma Grade única

A Grid adiciona alguma complexidade, mas usa apenas um único elemento de painel.

<Grid>
  <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <TextBlock Text="Options:" Grid.ColumnSpan="2" />
  <CheckBox Content="Power User" Grid.Row="1" Grid.ColumnSpan="2" />
  <CheckBox Content="Admin" Margin="150,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" />
  <TextBlock Text="Basic information:" Grid.Row="2" Grid.ColumnSpan="2" />
  <TextBlock Text="Name:" Width="75" Grid.Row="3" />
  <TextBox Width="200" Grid.Row="3" Grid.Column="1" />
  <TextBlock Text="Email:" Width="75" Grid.Row="4" />
  <TextBox Width="200" Grid.Row="4" Grid.Column="1" />
  <TextBlock Text="Password:" Width="75" Grid.Row="5" />
  <TextBox Width="200" Grid.Row="5" Grid.Column="1" />
  <Button Content="Save" Grid.Row="6" />
</Grid>

Opção 3: apenas um RelativePanel:

Esse único painel é um pouco mais complexo do que usar painéis aninhados, mas pode ser mais fácil de entender e manter do que uma Grade.

<RelativePanel>
  <TextBlock Text="Options:" x:Name="Options" />
  <CheckBox Content="Power User" x:Name="PowerUser" RelativePanel.Below="Options" />
  <CheckBox Content="Admin" Margin="20,0,0,0" 
            RelativePanel.RightOf="PowerUser" RelativePanel.Below="Options" />
  <TextBlock Text="Basic information:" x:Name="BasicInformation"
           RelativePanel.Below="PowerUser" />
  <TextBlock Text="Name:" RelativePanel.AlignVerticalCenterWith="NameBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="NameBox"               
           RelativePanel.Below="BasicInformation" />
  <TextBlock Text="Email:"  RelativePanel.AlignVerticalCenterWith="EmailBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="EmailBox"
           RelativePanel.Below="NameBox" />
  <TextBlock Text="Password:" RelativePanel.AlignVerticalCenterWith="PasswordBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="PasswordBox"
           RelativePanel.Below="EmailBox" />
  <Button Content="Save" RelativePanel.Below="PasswordBox" />
</RelativePanel>

Como esses exemplos mostram, há muitas maneiras de alcançar a mesma interface do usuário. Você deve escolher considerando cuidadosamente todas as compensações, incluindo desempenho, legibilidade e manutenção.

Utilizar grades de célula única para sobreposição da interface do usuário

Um requisito comum da interface do usuário é ter um layout em que os elementos se sobreponham. Normalmente, preenchimento, margens, alinhamentos e transformações são usados para posicionar os elementos dessa maneira. O controle da Grade XAML é otimizado para melhorar o desempenho do layout para elementos que se sobrepõem.

Importante Para ver a melhoria, use uma grade de de célula única. Não defina RowDefinitions ou ColumnDefinitions.

Exemplos

<Grid>
    <Ellipse Fill="Red" Width="200" Height="200" />
    <TextBlock Text="Test" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" />
</Grid>

Texto sobreposto em um círculo

<Grid Width="200" BorderBrush="Black" BorderThickness="1">
    <TextBlock Text="Test1" HorizontalAlignment="Left" />
    <TextBlock Text="Test2" HorizontalAlignment="Right" />
</Grid>

Dois blocos de texto em uma grade

Usar as propriedades de borda internas de um painel

Grid, StackPanel, RelativePanele controles ContentPresenter têm propriedades de borda internas que permitem desenhar uma borda em torno deles sem adicionar um elemento Border adicional ao seu XAML. As novas propriedades que dão suporte à borda interna são: BorderBrush, BorderThickness, CornerRadiuse Padding. Cada um deles é um DependencyProperty, para que você possa usá-los com associações e animações. Eles foram projetados para serem um substituto completo para um elemento Border separado.

Se a interface do usuário tiver elementos borda ao redor desses painéis, use a borda incorporada, que economiza um elemento extra na estrutura de layout do seu aplicativo. Conforme mencionado anteriormente, isso pode ser uma economia significativa, especialmente no caso de interface do usuário repetida.

Exemplos

<RelativePanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
    <TextBox x:Name="textBox1" RelativePanel.AlignLeftWithPanel="True"/>
    <Button Content="Submit" RelativePanel.Below="textBox1"/>
</RelativePanel>

Usar eventos SizeChanged para responder às alterações de layout

A classe FrameworkElement expõe dois eventos semelhantes para responder a alterações de layout: LayoutUpdated e SizeChanged. Você pode estar usando um desses eventos para receber notificação quando um elemento é redimensionado durante o layout. A semântica dos dois eventos é diferente e há considerações importantes sobre o desempenho na escolha entre eles.

Para um bom desempenho, SizeChanged é quase sempre a escolha certa. SizeChanged tem semântica intuitiva. É gerado durante o layout quando o tamanho do FrameworkElement é atualizado.

layoutUpdated também é gerado durante o layout, mas tem semântica global, ele é gerado em todos os elementos sempre que qualquer elemento é atualizado. É comum fazer apenas o processamento local no manipulador de eventos, nesse caso, o código é executado com mais frequência do que o necessário. Use LayoutUpdated somente se precisar saber quando um elemento é reposicionado sem alterar o tamanho (o que é incomum).

Escolhendo entre painéis

Normalmente, o desempenho não é uma consideração ao escolher entre painéis individuais. Essa escolha normalmente é feita considerando qual painel fornece o comportamento de layout mais próximo da interface do usuário que você está implementando. Por exemplo, se você estiver escolhendo entre Grid, StackPanel e RelativePanel, deverá escolher o painel que fornece o mapeamento mais próximo ao seu modelo mental da implementação.

Cada painel XAML é otimizado para um bom desempenho e todos os painéis fornecem desempenho semelhante para interface do usuário semelhante.