O sistema de layout
Este tópico descreve o sistema de layout do Windows Presentation Foundation (WPF). Entender as noções básicas sobre como e quando ocorrem os cálculos de layout é essencial na criação de interfaces de usuário visualmente bonitas e de alto desempenho.
Este tópico contém as seguintes seções.
O sistema de layout
Caixas delimitadoras de elementos
Medindo e organizando filhos
Elementos Panel e comportamentos de layout personalizados
Considerações sobre desempenho de layout
O Que Mais Há
Tópicos relacionados
O sistema de layout
O termo "layout" descreve o processo de medição e organização dos membros da coleção Children de um elemento Panel e seu posterior desenho na tela. Este é um processo intensivo e quanto maior a coleção Children, maior o número de cálculos feitos. Complexidade também pode ser introduzida com base no comportamento de layout definido pelo elemento Panel que é dono da coleção. Um layout relativamente simples, como Canvas, pode produzir excelente desempenho quando um Panel mais complexo, como um Grid, não é necessário.
Sempre que um UIElement filho altera sua posição ele pode potencialmente disparar uma nova passagem pelo sistema de layout. Dessa forma, é importante compreender os eventos que podem chamar o sistema de layout, já que chamadas desnecessárias podem levar a um desempenho ruim do aplicativo.
Na sua forma mais simples, layout é um sistema recursivo que faz com que um elemento seja dimensionado, posicionado e desenhado na tela. O sistema de layout completa duas passagens para cada membro da coleção Children, uma passagem de medição e uma passagem de organização. Cada Panel filho fornece seus próprios métodos MeasureOverride e ArrangeOverride de modo a atingir seu comportamento específico de layout. Esta é a série de eventos que ocorre sempre que o sistema de layout é invocado.
Um UIElement filho começa o processo de layout tendo suas propriedades principais medidas.
As propriedades de dimensionamento definidas em FrameworkElement são avaliadas, como Width, Height e Margin.
A lógica específica do Panel é aplicada, como direção de Dock ou Orientation de empilhamento.
O conteúdo é organizado após todos os filhos terem sido medidos.
A coleção Children é desenhada na tela.
O processo é chamado novamente se Children adicionais são adicionadas à coleção, um LayoutTransform é aplicado, ou o método UpdateLayout é chamado.
Esse processo e os meios pelos quais ele é chamado, são definidos em mais detalhes nas seções a seguir.
Caixas delimitadoras de elementos
Quando se está pensando no layout de um aplicativo no Windows Presentation Foundation (WPF), é importante compreender a caixa delimitadora que circunda todos os elementos. Este abstração auxilia na compreensão do comportamento do sistema de layout. Cada FrameworkElement consumido pelo sistema de layout pode ser considerado como um retângulo que é encaixado em uma partição do layout. Uma classe, LayoutInformation, é exposta que pode retornar os limites geométricos da alocação ou do encaixe de layout de um elemento. O tamanho do retângulo é determinado pelo sistema, através do cálculo do espaço disponível na tela, o tamanho de quaisquer restrições, propriedades específicas de layout como margem e preenchimento e o comportamento individual do elemento Panel pai. Processando esses dados, o sistema é capaz de calcular a posição de todos os filhos de um determinado Panel. É importante lembrar que as características de dimensionamento definidas no elemento pai (tal como uma Border) afetam seus filhos.
Como exemplo, considere o seguinte cenário simples de layout.
Este layout pode ser alcançado usando o seguinte Extensible Application Markup Language (XAML).
<Grid Name="myGrid" Background="LightSteelBlue" Height="150">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0" Grid.Row="0">Hello World!</TextBlock>
<Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0" Grid.Row="1">Show Bounding Box</Button>
<TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>
O elemento TextBlock está hospedado em um Grid, e enquanto o texto preenche apenas o canto superior esquerdo da coluna na qual ele foi colocado, o espaço alocado para o TextBlock é muito maior. A caixa delimitadora de qualquer FrameworkElement pode ser recuperada usando o método GetLayoutSlot. Usando esse método, a caixa delimitadora do elemento TextBlock é sobreposta (isso é possível porque o TextBlock está hospedado em um Grid, um elemento Panel que permite o compartilhamento de coordenadas de layout).
Como agora está aparente, devido à linha em branco que o circunda, a partição alocada para o elemento TextBlock é realmente muito maior do que o espaço que ele preenche. A medida que outros elementos são adicionados ao Grid, essa alocação poderia reduzir-se ou expandir-se, dependendo do tipo e tamanho dos elementos que são adicionados.
O encaixe de layout do TextBlock é retornado e convertido em um Path usando o método GetLayoutSlot, uma técnica que pode ser útil para exibir a caixa delimitadora de um elemento.
Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim myRectangleGeometry As New RectangleGeometry
myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)
Dim myGeometryDrawing As New GeometryDrawing
Dim myPath As New Path
myPath.Data = myRectangleGeometry
myPath.Stroke = Brushes.LightGoldenrodYellow
myPath.StrokeThickness = 5
Grid.SetColumn(myPath, 0)
Grid.SetRow(myPath, 0)
myGrid.Children.Add(myPath)
txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString()
End Sub
private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{
RectangleGeometry myRectangleGeometry = new RectangleGeometry();
myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
GeometryDrawing myGeometryDrawing = new GeometryDrawing();
Path myPath = new Path();
myPath.Data = myRectangleGeometry;
myPath.Stroke = Brushes.LightGoldenrodYellow;
myPath.StrokeThickness = 5;
Grid.SetColumn(myPath, 0);
Grid.SetRow(myPath, 0);
myGrid.Children.Add(myPath);
txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString();
}
Medindo e organizando filhos
Quando o conteúdo de um objeto Window é renderizado, o sistema de layout é invocado automaticamente. Para exibir conteúdo, o Content da janela deve definir um Panel raiz que serve para definir uma estrutura pela qual os elementos Children são organizados na tela. Consulte Elementos Panel e comportamentos personalizados de layout para obter uma lista de elementos Panel disponíveis e informações sobre como criar elementos de layout personalizados.
A primeira passagem de layout é a passagem de medição, na qual cada membro da coleção Children é avaliado. O processo se inicia com uma chamada ao método Measure. Este método é chamado dentro da implementação do elemento Panel pai e não precisa ser chamado explicitamente para o layout ocorrer.
Primeiro, as propriedades de tamanho nativo do UIElement são avaliadas, como Clip e Visibility. Isso gera um valor chamado constraintSize que é passado para MeasureCore.
Em segundo lugar, as propriedades do framework definidas no FrameworkElement são processadas, afetando o valor de constraintSize. Essas propriedades tendem a descrever as características de dimensionamento do UIElement subjacente, tais como Height, Width, Margin e Style. Cada uma dessas propriedades pode alterar o espaço necessário para exibir o elemento. MeasureOverride é então chamado com constraintSize sistema autônomo um parâmetro.
Observação: |
---|
Há uma diferença entre as propriedades de Height e Width e ActualHeight e ActualWidth. Por exemplo, a propriedade ActualHeight é um valor calculado com base nas outras entradas de altura e no sistema de layout. O valor é definido pelo sistema de layout em si, com base em uma passagem de renderização e pode, portanto, ficar um pouco diferente do valor definido para propriedades como Height que são a base das alterações de entrada. Porque ActualHeight é um valor calculado, você deve estar ciente de que pode haver vários ou relatados incremental muda para ela sistema autônomo resultado de várias operações pelo sistema de layout. O sistema de layout pode estar calculando o espaço dimensionado necessário para os elementos filho, as restrições do elemento pai e assim por diante. |
O objetivo final da passagem de medição é os filhos determinarem seu DesiredSize, o que ocorre durante a chamada a MeasureCore. Esse valor é armazenado por Measure para uso durante o processo de organizar o conteúdo.
O processo de arrumação se inicia com uma chamada ao método Arrange. Durante a etapa de organização, o elemento Panel pai gera um retângulo que representa os limites dos filhos. Esse valor é passado para o método ArrangeCore para processamento.
The ArrangeCore método avalia o DesiredSize do filho e avalia qualquer margem adicionais que pode afetar o dimensionar do elemento processado e gera um arrangeSize, que é passado para a ArrangeOverride painel do sistema autônomo um parâmetro. ArrangeOverride gera o finalSize do filho e, finalmente, o ArrangeCore método oferece uma avaliação final de deslocamento propriedades sistema autônomo a margem e o alinhamento e coloca o filho dentro de seu slot de layout. O filho não precisa (e com frequência não vai) preencher todo o espaço alocado. O controle, em seguida, é retornado para o Panelpai , e o processo de layout é concluído.
Elementos Panel e comportamentos de layout personalizados
O Windows Presentation Foundation (WPF) inclui um conjunto de elementos Panel que permite vários layouts complexos. Cenários comuns, como empilhar elementos, podem facilmente ser alcançados usando o elemento StackPanel, enquanto layouts mais complexos e de fluxo livre são possíveis usando-se um Canvas.
A tabela a seguir resume os elementos de layout disponíveis.
Nome do painel |
Descrição |
---|---|
Defines an area within which you can explicitly position child elements by coordinates relative to the Canvas area. |
|
Defines an area within which you can arrange child elements either horizontally or vertically, relative to each other. |
|
Defines a flexible grid area consisting of columns and rows. |
|
Arranges child elements into a single line that can be oriented horizontally or vertically. |
|
Fornece uma estrutura para elementos Panel que "virtualiza" suas coleção de filhos. Esta é uma classe abstrata. |
|
Posiciona elementos filhos em uma posição sequencial da esquerda para a direita, quebrando o conteúdo para a próxima linha no limite da caixa delimitadora. Subsequent ordering happens sequentially from top to bottom or right to left, depending on the value of the Orientation property. |
Para exemplos de código mostrando o uso de cada um desses elementos, consulte Exemplos de layout.
Para cenários que necessitam de layouts de aplicativos que não sejam possíveis usando qualquer um dos elementos Panel predefinidos, comportamentos de layout personalizados podem ser obtidos ao herdar de Panel e sobrescrever os métodos MeasureOverride e ArrangeOverride. Para um exemplo, consulte Exemplo de painel radial Personalizar.
Considerações sobre desempenho de layout
Layout é um processo recursivo. Cada elemento filho em uma coleção Children é processado durante cada chamada ao sistema. Como resultado, deve-se evitar acionar o sistema quando não for necessário. As dicas a seguir podem ajudar a atingir um melhor desempenho.
Propriedades de dependência cujos valores podem fazer com que o sistema de layout a ser inicializado são marcadas com sinalizadores públicas. AffectsMeasure e AffectsArrange fornecem dicas úteis aos quais sistema autônomo alterações de valor da propriedade forçará uma recursiva atualizar o sistema de layout. Em geral, qualquer propriedade que pode afetar o tamanho da caixa delimitadora de um elemento deve definir o sinalizador AffectsMeasure como True. Para obter mais informações, por favor consulte: Visão geral sobre propriedades de dependência.
Uma LayoutTransform pode ser uma maneira muito útil para afetar o conteúdo de uma interface do usuário (UI). No entanto, se o efeito de transformação não precisar de afetar a posição dos outros elementos, é melhor usar um RenderTransform em vez disso, sistema autônomo RenderTransform não invoca o sistema de layout. LayoutTransform aplica a transformação e força uma atualização do layout recursiva para a nova posição do elemento afetado.
Evite chamadas desnecessárias a UpdateLayout. Esse método força uma atualização recursiva de layout e frequentemente não é necessário. A menos que você tenha certeza de que uma atualização completa é necessária, confie no sistema de layout para chamar esse método por você.
Ao lidar com uma coleção Children grande, considere o uso de VirtualizingStackPanel em vez de um StackPanel normal. Ao "virtualizar" a coleção de filhos, o VirtualizingStackPanel apenas mantém na memória os objetos que estão dentro da ViewPort do pai. Como resultado, o desempenho é significativamente aprimorado na maioria das situações.
O que mais?
Entender as noções básicas sobre como os elementos são medidos e organizados é o primeiro passo para entender o layout como um sistema. Para uma compreensão mais profunda dos elementos Panel disponíveis, consulte Panels Overview. Para compreender melhor as várias propriedades de posicionamento que podem afetar o layout, consulte Visão Geral sobre Alinhamento, Margens e Margens Internas. Para obter um exemplo de um elemento Panel personalizado, consulte Exemplo de painel radial Personalizar. Quando você estiver pronto para colocar tudo junto em um aplicativo leve, consulte Getting Started with Windows Presentation Foundation.
Consulte também
Conceitos
Visão Geral sobre Alinhamento, Margens e Margens Internas
Pixel Snapping in WPF Applications
Otimizando o desempenho: Layout and Design