O WPF (Windows Presentation Foundation) foi criado com o objetivo de fornecer possibilidades de desenvolvimento de interfaces ricas, ou seja, mais complexas e elaboradas que aquelas com as quais estamos acostumados em projetos Windows Forms, que geralmente assumem os padrões de interface do sistema operacional.

Utilizando XAML (Extensible Application Markup Language), uma linguagem de marcação baseada em XML criada para a elaboração da interface de aplicações WPF e Silverlight, podemos desenvolver aplicações com aparência muito mais elegante e com comportamentos que não seriam possíveis (ou requisitariam muito trabalho) em formulários comuns.

Um dos pontos mais básicos, porém de grande importância, em que e o WPF (ou a XAML) se mostra superior aos Windows Forms é na estruturação do layout das telas. Enquanto nos Windows Forms os controles são posicionados basicamente com base em suas coordenadas vertical e horizontal, apesar de termos algumas opções como a propriedade Dock e alguns elementos containers, em WPF existem vários controles cujo objetivo é posicionar os demais de forma eficiente e até adequada a qualquer resolução de tela.

Neste artigo conheceremos dois dos principais containers da linguagem XAML, disponíveis tanto para WPF quanto para Silverlight (incluindo a versão para Windows Phone), o StackPanel e o Grid. Veremos como funciona cada um e exemplos de utilização, que tornarão mais simples a compreensão de quando utilizar um ou outro em aplicações reais.

StackPanel

O StackPanel é utilizado para posicionar seus elementos filhos de forma linear, seja vertical ou horizontalmente. Os elementos inseridos dentro de um StackPanel são sempre dispostos um sob o outro ou um ao lado do outro, independentemente de sua altura ou largura, respectivamente.

O mais interessante nesse controle é que ao inserirmos os elementos filhos, não precisamos nos preocupar em organizá-los dentro do painel, pois isso é feito automaticamente. Ou seja, só precisamos definir as dimensões de cada elemento e a sua posição será determinada pelo StackPanel.

Para determinar se os elementos serão organizados de forma horizontal ou vertical, basta definir a propriedade Orientation do StackPanel como Horizontal ou Vertical.

Na Listagem 1 vemos um exemplo em que dispomos alguns botões verticalmente dentro de um StackPanel. Vale observar que apenas inserimos os botões e eles foram organizados verticalmente, pois esta é a orientação padrão do StackPanel. Logo, só é preciso definir a propriedade Orientation quando necessitarmos da orientação horizontal.

Listagem 1: Exemplo de uso do StackPanel

<StackPanel>
    <Button Content="LX"/>
    <Button Content="LMFC"/>
    <Button Content="LMFS"/>
    <Button Content="Espelho MFD"/>
    <Button Content="Arquivo MFD"/>
    <Button Content="Tabela de Produtos"/>
    <Button Content="Estoque"/>
    <Button Content="Movimento por ECF"/>
    <Button Content="Meios de Pagamento"/>
    <Button Content="Identificação do PAF-ECF"/>
</StackPanel>

O resultado é o seguinte:

Botões organizados no StackPanel

Figura 1: Botões organizados no StackPanel

Grid

O container Grid pode ser dividido em linhas e colunas e é mais utilizado para definir a estrutura mais abrangente de uma tela.

Para definir as linhas e colunas utilizamos as propriedades RowDefinitions e ColumnDefinitions, respectivamente. Estas são propriedades compostas e dentro delas são inseridos atributos do tipo RowDefinition e ColumnDefinition, contendo a altura da linha e a largura da coluna, nessa ordem.

Na Listagem 2 temos um exemplo de definição das linhas e colunas de um Grid, analisando-o se tornará mais fácil compreender como definir as larguras e alturas de cada divisão.

Listagem 2: Definindo as divisões de um Grid

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
</Grid>

Definimos que esse Grid contém 3 linhas e 3 colunas e suas alturas e larguras serão definidas da seguinte forma:

  • 100: indica uma dimensão de 100px (para a altura, no caso da linha, e para a largura, no caso da coluna;
  • *: indica que a linha ou coluna irá ocupar todo o espaço restante no container, que é o Grid.
  • Auto: indica que a altura da linha e a largura da coluna irão se adaptar às dimensões de seu conteúdo.

Uma vez definida a estrutura do Grid, podemos inserir os elementos filhos, que devem também ficar entre as marcações <Grid> e </Grid>. Em cada elemento filho precisamos definir sua posição no container, ou seja, em que linha e coluna ele será posicionado, caso contrário eles serão automaticamente inseridos na primeira linha e primeira coluna. Isso é feito definindo as propriedades Grid.Row e Grid.Column, indicando a linha e a coluna, respectivamente.

Também é possível fazer com que um elemento ocupe mais de uma linha ou coluna no Grid, basta informar as propriedades Grid.RowSpan e Grid.ColumnSpan com um número inteiro.

Abaixo temos um exemplo completo de layout utilizando um controle do tipo Grid.

Listagem 3: Exemplo de layout usando Grid

<Window x:Class="LayoutWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Consultar contrato" Height="300" Width="640">
<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="30"/>
        <RowDefinition Height="5"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
    <Label Content="Consultar contratos por cliente" Grid.ColumnSpan="3"
            Grid.Row="0" Grid.Column="0" FontSize="40"/>
    <Label Content="Nome do cliente:" Grid.Row="1"/>
    <TextBox Grid.Row="1" Grid.Column="1"/>
    <Button Content="Consultar" Grid.Row="1" Grid.Column="2"/>
    <DataGrid Grid.Row="3" Grid.ColumnSpan="3">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Nº Contrato"/>
            <DataGridTextColumn Header="Data de Emissão"/>
            <DataGridTextColumn Header="Valor (R$)"/>
            <DataGridTextColumn Header="CPF Cliente"/>
            <DataGridTextColumn Header="Nome Cliente"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
</Window>

Neste pequeno exemplo utilizamos vários dos conceitos e propriedades que já vimos.

Este layout em tempo de execução tem a seguinte aparência:

Exemplo com Grid em execução

Figura 2: Exemplo com Grid em execução

Conclusão

Como vimos, os controles Grid e StackPanel são bem diferentes e apesar de terem como objetivo organizar elementos na tela, o fazem de forma diferente, sendo o Grid um tanto mais complexo que o StackPanel. Porém, cada um tem sua aplicação e o conhecimento de ambos é fundamental para quem trabalha ou deseja trabalhar com XAML, seja em WPF ou em Silverlight.