If you consider the examples that have been
shown, you may have missed the importance of XAML containers. The most
obvious of these can be seen in the Grid
element:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock Text="Hello" />
</Grid>
</UserControl>
The purpose of these containers is to allow other elements to be laid
out in particular ways on the visual surface of XAML. The containers
themselves typically don’t have any user interface but simply are used
to determine how different XAML elements are arranged on the screen. A
number of layout containers are important to designing in XAML. Each of
these can contain one or more child elements and lay them out in
specific ways. You can see the common visual containers in Table 1.
Table 1. Visual Containers
These containers are important as they are used to determine how your elements are laid out. The most important of these is the Grid
container and it will be the one you use most often. The Grid
is a container that supports dynamic, table-like layout using rows and columns. To define rows and columns, you set the Grid
’s ColumnDefinitions
and/or RowDefinitions
properties. These properties take one or more ColumnDefinition
or RowDefinition
elements, as shown in the following code:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="Hello" />
</Grid>
</UserControl>
You create new columns and rows using the ColumnDefinitions
and RowDefinitions
properties (as shown). This allows you to specify that individual elements are in a particular row or column using the Grid.Column
or Grid.Row
attached properties (see the sidebar, What Are Attached Properties?):
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="Hello"
Grid.Column="1" /> <!-- The Second Column -->
</Grid>
</UserControl>
By using the attached property, the TextBlock
is indicating that the TextBlock
belongs in the second column (note that row and column numbers are zero-indexed). In this way, the Grid
is creating columns or rows proactively by specifying the number of
rows or columns up front. At first blush it may seem verbose to create
row and/or column definitions this way, but it’s important as the
definitions contain other important information that can be set.
When creating rows and columns, you can define the height or width (respectively) in three ways, as shown in Table 2.
Table 2. Grid
Row and Column Sizing
Auto and pixel sizing are pretty self-explanatory, but star sizing
requires some explanation. Star sizing proportionally sizes rows or
columns based on the values of the height or width. For example:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="33*" />
<ColumnDefinition Width="66*" />
</Grid.ColumnDefinitions>
</Grid>
</UserControl>
The width values are used as weighted proportions of the whole size.
While this looks similar to percentages (like you may be used to in Web
applications), the numbers are not part of an arbitrary 100% scale. For
example, changing the values to "1*"
and "2*"
will yield the same 2-to-1 ratio as "33*"
and "66*"
. In the case of using a star alone (e.g., “*”), it is equivalent to "1*"
. By using Grid
elements with a mix of auto, pixel, and star sizing, you can create
elastic layouts (using star sizing for the flexible sized elements and
pixel/auto sizing for the more static parts of the design).
You have already seen that you can use attached properties to set the row and/or column of a specific element inside the Grid
. The Grid
class also supports the ability to specify RowSpan
and ColumnSpan
to signify that a particular element should span more than one row
and/or column. This will give you extra flexibility to create your
table-based designs, like so:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="1" />
<TextBlock Text="1"
Grid.Row="1" />
<TextBlock Text="1"
Grid.Column="1" />
<TextBlock Text="Across All 3 Columns"
Grid.ColumnSpan="3" />
<TextBlock Text="Across Both Rows"
Grid.RowSpan="2" />
</Grid>
Although you may use the other layout containers in certain cases, you should become comfortable with the Grid
as it is the container you will use most often.