Taking another look at Example 1-22 with the TextBlock
and the Image
as content for the Button
, we don't really have enough
information to place them inside the area of the button. Should they be
stacked left to right or top to bottom? Should one be docked on one edge
and one docked to the other? How will things be stretched or arranged if
the button resizes? These are questions best answered with a panel.
A panel is a control that knows how to arrange its content. WPF comes with the following general-purpose panel controls:
Canvas
Arranges content by position and size with no automatic rearrangement when the
Canvas
is resizedDockPanel
Arranges content according to the edge that each piece of content "docks" to, except for the last, which fills the remaining area
Grid
Arranges content in rows and columns as specified by the developer
StackPanel
Arranges content top to bottom or left to right according to the orientation of the panel
UniformGrid
Arranges content in a grid with the same number of rows and columns generated as needed to display the content
WrapPanel
Arranges things in a horizontal row until the next item won't fit, in which case it wraps to the next row
The most flexible panel by far is the grid, which arranges content elements in rows and columns, including the ability to span multiple rows and/or multiple columns, as shown in Example 1-23.
Example 1-23. A sample usage of the Grid panel
<Window ...> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <ButtonGrid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
>A</Button> <ButtonGrid.Row="0" Grid.Column="2"
>C</Button> <ButtonGrid.Row="1" Grid.Column="0" Grid.RowSpan="2"
>D</Button> <ButtonGrid.Row="1" Grid.Column="1"
>E</Button> <ButtonGrid.Row="1" Grid.Column="2"
>F</Button> <ButtonGrid.Row="2" Grid.Column="1"
>H</Button> <ButtonGrid.Row="2" Grid.Column="2"
>I</Button> </Grid> </Window>
Example 1-23 used the
XAML property element syntax to define a grid with three rows and
three columns inside the RowDefinition
and ColumnDefinition
elements. On each element,
we've specified the Grid.Row
and
Grid.Column
properties so that the
grid knows which elements go where (the grid can have multiple
elements in the same cell). One of the elements spans two rows and one
spans two columns, as shown in Figure 1-13.
Using the grid, we can be explicit about how we want to arrange an image with a text caption (Example 1-24).
Example 1-24. Arranging an image and text in a grid
<Button Width="100" Height="100">
<Button.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Grid.Row="0"
Source="tom.png" />
<TextBlock
Grid.Row="1"
HorizontalAlignment="Center">Tom</TextBlock>
</Grid>
</Button.Content>
</Button>
Figure 1-14 shows how the grid arranges the image and text for us.
Because we're just stacking one element on top of another, we could've used the stack panel, but the grid is so general-purpose that many WPF programmers find themselves using it for most layout configurations.
You may have noticed that in setting up the Grid.Row
and Grid.Panel
attributes of the Button
elements, we used another dotted
syntax, similar to the property element syntax, but this time on the
attribute instead of on the element. This is the attached property syntax, and it is used to
set a property as associated with the particular element (e.g., a
Button
), but as defined by another
element (e.g., a Grid
).
The attached property syntax is used in WPF as an extensibility
mechanism. We don't want the Button
class to have to know that it's being arranged in a Grid
, but we do want to specify Grid
-specific attributes on it. If the
Button
was being hosted in a
Canvas
, the Grid
properties wouldn't make any sense, so
building Row
and Column
properties into the Button
class isn't such a great idea.
Further, when we define our own custom panel that the WPF team never
considered (e.g., HandOfCards
), we
want to be able to apply the HandOfCards
-related attached properties to
arbitrary elements it contains.
This kind of extensibility is what the attached property syntax was designed for and it is common when arranging content on a panel.
For the nitty-gritty of layout, including the other panels that I didn't show, you'll want to read Chapter 3.
Get Programming WPF, 2nd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.