#409 – Child Elements in a Grid Size to Fit the Containing Cell

By default, most child elements hosted in a Grid will automatically size to fit the size of the containing cell.  You typically do not set explicit sizes for child elements, but control their size by changing the size of the corresponding rows or columns in the Grid.

You can also control the size of the child elements by using the Margin property to specify how much space should exist between the outside edge of the control and the boundaries of the cell.

    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Larry" Margin="5" Background="Lavender"/>
        <Label Grid.Row="0" Grid.Column="1" Content="Moe" Margin="5" Background="Magenta"/>
        <Label Grid.Row="0" Grid.Column="2" Content="Curly" Margin="5" Background="Cornsilk"/>

        <CheckBox Grid.Row="1" Grid.Column="0" Margin="5" Content="Nose Tweak"/>
        <Button Grid.Row="1" Grid.Column="1" Margin="5" Content="Do Eye Poke" />
        <TextBox Grid.Row="1" Grid.Column="2" Margin="5" Text="Double slap"/>
    </Grid>



#408 – ShowGridLines Property Allows You to See Individual Cells in Grid

When laying out child elements in a Grid, it can be helpful to get some visual indication of where the grid’s individual cells are located.  You can do this by setting the ShowGridLines property of the Grid to true.  A dotted line will appear, showing the boundaries of the rows and columns.

This property is meant to be used only at design time, to assist in laying out the elements of the Grid–the expectation is that you’d set ShowGridLines to false before shipping an application.

    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Larry" Margin="10" Background="Lavender"/>
        <Label Grid.Row="0" Grid.Column="1" Content="Moe" Margin="10" Background="Magenta"/>
        <Label Grid.Row="0" Grid.Column="2" Content="Curly" Margin="10" Background="Cornsilk"/>

        <Button Grid.Row="1" Grid.Column="1" Content="Do Eye Poke" Margin="10"/>
    </Grid>


As I resize the parent window, causing the Grid to change size, you can see how the size of the individual cells changes.

#407 – Grid Contains Single Row and Column by Default

If you define a Grid, but do not define any rows or columns using the RowDefinitions and ColumnDefinitions properties, the resulting grid will contain a single row and a single column.

    <Grid>
        <Button Content="I'm in a Grid" Margin="5"/>
    </Grid>


Similarly, if you define a Grid and specify multiple columns using the ColumnDefinitions property, but not the RowDefinitions property, you’ll get a single row and the specified number of columns.  (The same is true for a single column and explicit number of rows).

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Content="Larry" Margin="10" Background="Lavender"/>
        <Label Grid.Column="1" Content="Moe" Margin="10" Background="Magenta"/>
        <Label Grid.Column="2" Content="Curly" Margin="10" Background="Cornsilk"/>
    </Grid>



#406 – Creating New Controls by Layering One on Top of Another

Because you can place more than one control in the same cell of a Grid, you can overlay multiple controls in order to create a new control.

As an example, assume that you want to add a Label to a ProgressBar, showing the current progress of some operation.  We can do this by placing a Label and a ProgressBar into the same cell of a Grid.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <!-- ProgressBar and Label overlayed, both in 1st row -->
        <ProgressBar Grid.Row="0" Value="{Binding Progress, Mode=OneWay}" Margin="5"/>
        <Label Grid.Row="0" Content="{Binding ProgressLabel}" HorizontalContentAlignment="Center" Margin="5"/>

        <Button Grid.Row="1" Content="Click to Start Progress" Click="StartTimer" Margin="5"/>
    </Grid>



#405 – Default Values for Grid.Row and Grid.Column Properties

You normally specify values for the Grid.Row and Grid.Column properties for each child element of a grid, indicating the cell in the grid where you’d like the child element positioned.

If you do not specify a value for either the Grid.Row or the Grid.Column properties, a value of 0 will be used for that property.  This places the element into the first row and/or first column, respectively.

In the example below, we’ve created a grid that has two rows and two columns.  We’ve mistakenly left off the Grid.Row and Grid.Column properties for the two child elements and so they have both been placed into the first row and first column.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Button Content="Push Me" Width="100" />
        <Label Content="Oops I'm in the same cell with a button !" />
    </Grid>

#404 – A Grid Hosts Child Controls in Rows and Columns

A Grid is a layout container that positions its child elements into a series of rows and columns.  You specify the number of rows and columns, along with information about their size, in the Grid tag.  You then specify which row and column each control is located in using the Grid.Row and Grid.Column attached properties.

Rows are numbered top to bottom, starting at 0.  Columns are numbered left to right, starting at 0.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0"
               Content="Upper left"/>
        <Label Grid.Row="0" Grid.Column="1"
               Content="Upper right"/>
        <Label Grid.Row="1" Grid.Column="0"
               Content="Lower left"/>
        <Label Grid.Row="1" Grid.Column="1"
               Content="Lower right"/>
    </Grid>

#403 – The Order of DockPanel Children Matters

The layout and appearance of child elements in a DockPanel control is based not only on the Dock property of each child element, but on the order that they are listed in.  This is true because layout of a child is determined based on the available space left after all previous children have already been positioned.

In the example below, we add two Label controls at the top and bottom of the window and then add a StackPanel with buttons after that.

    <DockPanel LastChildFill="False">
        <Label Content="Some intro could go here, across the top" DockPanel.Dock="Top" Background="AliceBlue"/>
        <Label Content="Some pithy quote could go here, on the bottom" DockPanel.Dock="Bottom" Background="LightSteelBlue"/>

        <StackPanel DockPanel.Dock="Left" Background="Cornsilk">
            <Button Content="Open" Margin="5"/>
            <Button Content="Close" Margin="5"/>
            <Button Content="Save" Margin="5"/>
            <Button Content="Export" Margin="5"/>
        </StackPanel>
    </DockPanel>


If we move the StackPanel to be the first child of the DockPanel, it takes up the entire left edge of the window.

#402 – Final Child of DockPanel Fills Remaining Space by Default

By default, the last child in the list of child elements of a DockPanel will automatically grow to fill the available space, regardless of the value of the DockPanel.Dock property.

    <DockPanel>
        <Label Content="1st label (Top)" DockPanel.Dock="Top" Background="Bisque"/>
        <Label Content="2nd (Left)" DockPanel.Dock="Left" Background="BurlyWood"/>
        <Label Content="3rd fills remaining space" DockPanel.Dock="Top" Background="Cornsilk"/>
    </DockPanel>

This happens because the DockPanel has a property called LastChildFill that defaults to true.  If we set it to false, we can then dock the last child element–and it will not fill all of the available space.

    <DockPanel LastChildFill="False">
        <Label Content="1st label (Top)" DockPanel.Dock="Top" Background="Bisque"/>
        <Label Content="2nd (Left)" DockPanel.Dock="Left" Background="BurlyWood"/>
        <Label Content="3rd fills remaining space" DockPanel.Dock="Top" Background="Cornsilk"/>
    </DockPanel>

#401 – DockPanel Element

The DockPanel element serves as a container for a collection of child elements, positioning its children by docking them to one of the sides of the container.  For each of the child elements, you specify a value for the DockPanel.Dock property, which can have one of the following values: Left, Top, Right or Bottom.

The location of each child is calculated one at a time, based on their order.  Each child is docked to one of the sides and stretched to fill the available space.  At each step, the docking/sizing happens within the remaining open space in the DockPanel.

    <DockPanel>
        <Label Content="1st label (Top)" DockPanel.Dock="Top" Background="Bisque"/>
        <Label Content="2nd (Left)" DockPanel.Dock="Left" Background="BurlyWood"/>
        <Label Content="3rd (Top)" DockPanel.Dock="Top" Background="Cornsilk"/>
        <Label Content="4th (Right)" DockPanel.Dock="Right" Background="DarkKhaki"/>
        <Label Content="5th (Bottom)" DockPanel.Dock="Bottom" Background="DarkSeaGreen"/>
        <Label Content="6th (Left)" DockPanel.Dock="Left" Background="Gainsboro"/>
        <Label Content="7th, fills remaining space" Background="Khaki"/>
    </DockPanel>

Resizing:

#400 – Using a WrapPanel as the Items Panel for a ListBox

The ItemsPanel property of a ListBox specifies the template that defines the panel used to contain the elements of the ListBox.  You can override the normal vertically stacked layout of a ListBox by defining your own template.

If you set the ItemsPanel template to contain a WrapPanel, the ListBox will show its child elements left to right, wrapping to the next row when each row fills up.

In the example below, we bind a ListBox to a list of movies, specify an ItemTemplate that dictates how each item appears, and then specify a template for the ItemsPanel that contains a WrapPanel.

    <Grid>
        <ListBox ItemsSource="{Binding MovieList}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical">
                        <Image Source="{Binding Image}" Stretch="None"/>
                        <Label Content="{Binding TitleWithYear}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" Orientation="Horizontal"  />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Grid>

Notice that the layout changes as we resize the parent window.