Layouts

Windows Presentation Foundation provides a number of container elements that fulfill the specialized purpose of layouts. Unlike most WPF controls, they can have multiple children, which they organize on-screen. And unlike Windows Forms, these layouts adjust to the available space.

Let’s examine each of five layouts in turn:

The Grid

The default layout is the Grid , which lays out its children elements in a grid pattern. A <Grid> is composed of columns and rows, the number and characteristics of which are defined by the grid’s ColumnDefinitions and RowDefinitions properties. These consist of a collection of ColumnDefinition and <RowDefinition/> elements. Each <ColumnDefinition/> is typically given a Width property value, while each <RowDefinition/> is given a Height property value.

Thus, you might expect the code:

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="200"/>
    <ColumnDefinition Width="200"/>
    <ColumnDefinition Width="200"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="100"/>
    <RowDefinition Height="100"/>
  </Grid.RowDefinitions>
  <Button Height="30" Width="120" Content="Click Me!"/>
</Grid>

Creates a grid with three columns, each 200 logical units wide, and two rows, each 100 logical units high. However, it will actually create a grid like this:

The resulting Grid The resulting Grid

Remember, all WPF containers will fill the available space - so the grid stretches the last column and row to fill the remaining space. Also, any element declared as a child of the grid (in this case, our button), will be placed in the first grid cell - [0,0] (counted from the top-left corner).

When declaring measurements in WPF, integer values correspond to logical units, which are 1/96th of an inch. We can also use relative values, by following a measurement with a *. This indicates the ratio of remaining space a column or row should take up after the elements with an exact size are positioned. I.e. a column with a width of 2* will be twice as wide as one with a width of 1*.

Thus, to create a 3x3 grid centered in the available space to represent a game of Tic-Tac-Toe we might use:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="100"/>
        <RowDefinition Height="100"/>
        <RowDefinition Height="100"/>
        <RowDefinition Height="1*"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Column="1" Grid.Row="1" FontSize="100" VerticalAlignment="Center" HorizontalAlignment="Center">X</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="2" FontSize="100" VerticalAlignment="Center" HorizontalAlignment="Center">O</TextBlock>
    <TextBlock Grid.Column="2" Grid.Row="1" FontSize="100" VerticalAlignment="Center" HorizontalAlignment="Center">X</TextBlock>        
</Grid>

Which would create:

The resulting Tic-Tac-Toe grid The resulting Tic-Tac-Toe grid

Note too that we use the properties Grid.Column and Grid.Row in the <TextBlock> elements to assign them to cells in the grid. The row and column indices start at 0 in the upper-left corner of the grid, and increase to the right and down.

The StackPanel

The StackPanel arranges content into a single row or column (defaults to vertical). For example, this XAML:

<StackPanel>
    <Button>Banana</Button>
    <Button>Orange</Button>
    <Button>Mango</Button>
    <Button>Strawberry</Button>
    <Button>Blackberry</Button>
    <Button>Peach</Button>
    <Button>Watermelon</Button>
</StackPanel>

Creates this layout:

The StackPanel Example The StackPanel Example

The StackPanel can be set to a horizontal orientation by setting its Orientation property to Horizontal:

<StackPanel Orientation="Horizontal">
    <Button>Banana</Button>
    <Button>Orange</Button>
    <Button>Mango</Button>
    <Button>Strawberry</Button>
    <Button>Blackberry</Button>
    <Button>Peach</Button>
    <Button>Watermelon</Button>
</StackPanel>

The WrapPanel

The WrapPanel layout is like the <StackPanel>, with the additional caveat that if there is not enough space for its contents, it will wrap to an additional line. For example, this XAML code:

<WrapPanel>
    <Button>Banana</Button>
    <Button>Orange</Button>
    <Button>Mango</Button>
    <Button>Strawberry</Button>
    <Button>Blackberry</Button>
    <Button>Peach</Button>
    <Button>Watermelon</Button>
</WrapPanel>

Produces this layout when there is ample room:

The WrapPanel Example The WrapPanel Example

And this one when things get tighter:

The Squeezed WrapPanel Example The Squeezed WrapPanel Example

The DockPanel

The DockPanel layout should be familiar to you - it’s what Visual Studio uses. Its content items can be ‘docked’ to one of the sides, as defined by the Dock enum: Bottom, Top, Left, or Right by setting the DockPanel.Dock property on that item. The last item specified will also fill the central space. If more than one child is specified for a particular side, it will be stacked with that side.

Thus, this XAML:

<DockPanel>
    <Button DockPanel.Dock="Top">Top</Button>
    <Button DockPanel.Dock="Left">Left</Button>
    <Button DockPanel.Dock="Right">Right</Button>
    <Button DockPanel.Dock="Bottom">Bottom</Button>
    <Button>Center</Button>
</DockPanel>

Generates this layout:

The DockPanel Example The DockPanel Example

The Canvas

Finally, the Canvas lays its content out strictly by their position within the <Canvas>, much like Windows Forms. This approach provides precise placement and size control, at the expense of the ability to automatically adjust to other screen resolutions. For example, the code:

<Canvas>
    <Button Canvas.Top="40" Canvas.Right="40">Do Something</Button>
    <TextBlock Canvas.Left="200" Canvas.Bottom="80">Other thing</TextBlock>
    <Canvas Canvas.Top="30" Canvas.Left="300" Width="300" Height="300" Background="SaddleBrown"/>
</Canvas>

Creates this layout:

The Canvas Example The Canvas Example

If there is a chance the <Canvas> might be resized, it is a good idea to anchor all elements in the canvas relative to the same corner (i.e. top right) so that they all are moved the same amount.