#1,168 – Layout in Action, part V

When a panel is laying out its children, it will respect (make use of) an explicit size specified for a child control.

In the example below, the MyLabel control specifies a width of 100.  This makes it wider than it would normally be to fit its content.

    <StackPanel Margin="5" Background="Honeydew">
        <loc:MyLabel Content="Billy" HorizontalAlignment="Center" Width="100"
                     Background="Thistle" />
    </StackPanel>

1168-001
At run-time, the measure/arrange process is:

  • StackPanel reads the label’s desired width of 100, using this value as the “constrained” width (target width)
  • StackPanel calls Measure on the label, with constrained width of 100 and height of Infinity
  • Label returns a size from MeasureOverride with width and height equal to what’s required for its content (31.4 wide x 26 high)
  • StackPanel calls Arrange on MyLabel, passing in a size that includes the explicit width (100 x 26)

1168-002

#1,042 – How FlowDirection Affects a StackPanel

Changing the FlowDirection property of a StackPanel changes how it lays out elements when its Orientation is set to Horizontal.

When Orientation is Horizontal and FlowDirection is LeftToRight (the default), each label’s width is set to fit its content.  The label’s height is stretched to fill the container.  Labels are arranged left to right.

1042-001

 

Changing FlowDirection to RightToLeft, the labels are arranged from right to left.

1042-002

 

If Orientation is Vertical and FlowDirection is LeftToRight, the labels’ width now sizes to fit the container and their height is set to match the content.  The labels are arranged from top to bottom in the StackPanel.

1042-003

Changing FlowDirection to RightToLeft when the orientation is Vertical does not change how the labels are arranged.  They are still ordered from top to bottom in the StackPanel.  The content of the labels, however, is now right-aligned, rather than left-aligned.

1042-004

#497 – Use a UniformGrid to Make a Group of Buttons the Same Size

You can use a StackPanel to make its child elements the same size in one of its dimensions.  This is harder to do in the other dimension.

The example below uses a StackPanel to contain some buttons.  They end up the same height, but are still different widths.

You can make the buttons the same height and width using a UniformGrid instead of a StackPanel.

        <UniformGrid DockPanel.Dock="Bottom" Margin="10" Rows="1" HorizontalAlignment="Right"
                    VerticalAlignment="Bottom">
            <Button Grid.Column="0" Content="No" FontSize="18" Margin="5" Padding="6,3"/>
            <Button Grid.Column="1" Content="Yes, Absolutely" Margin="5" Padding="6,3"/>
            <Button Grid.Column="2" Content="Maybe" Margin="5" Padding="6,3"/>
        </UniformGrid>

The UniformGrid will make sure that each cell is the same height and the same width.  This is desirable because you then avoid having to set the button sizes manually.

#496 – Using a StackPanel to Make a Group of Buttons the Same Size

You’ll often want to stack a group of buttons in a GUI, vertically or horizontally.  You’d typically use a StackPanel to do this.

Let’s say that you want a series of buttons stacked vertically on the right side of a window.

We can use a DockPanel as the main container and add a StackPanel docked on the right and oriented vertically.  But when we do this, the StackPanel expands to fill the available space, as does each Button.

The HorizontalAlignment of the StackPanel defaults to Stretch, as do each of the buttons.  We could set the HorizontalAlignment for each Button to Right, but the buttons now all size to fit their content, which is not quite what we want.

What we really want is for the HorizontalAlignment of each Button to be Stretch, but for the HorizontalAlignment of the StackPanel itself to be Right.  This gives us what we want.

#470 – Elements that Support RightToLeft Flow

Every FrameworkElement has a FlowDirection property that can be either LeftToRight (the default), or RightToLeft.  For panel elements that lay out a series of child elements, this property indicates in which direction the layout should be done.

The FlowDirection property is typically used for cultures where text flows from right to left, e.g. Arabic.  However, you can use this property whenever a right-to-left layout would make sense.

Below are some examples of elements that can use RightToLeft flow.

A Calendar control.

A DatePicker

A Menu, with MenuItem elements

A ListBox

A TreeView

A ProgressBar

A Grid

A StackPanel with Horizontal orientation

#445 – DockPanel Can Be Used Like a StackPanel

The DockPanel layout container is most often used to dock other container controls along each edge of a window and perhaps include a control that fills the remaining space.  This works well as the outermost container for a main application window.

But because you can stack multiple controls consecutively on the same side, you can use a DockPanel like a StackPanel, but stacking controls in any direction.

Docking everything to the left:

Docking everything to the right:

To the top:

Or the bottom:

You can also use various combinations, stacking a series of controls to one side and then another group of controls to another side.

    <DockPanel LastChildFill="False">
        <Button Content="1 - Button" DockPanel.Dock="Left"/>
        <Button Content="2 - Button" DockPanel.Dock="Left" />
        <Button Content="3 - Button" DockPanel.Dock="Left" />

        <Button Content="4 - Button" DockPanel.Dock="Bottom" />
        <Button Content="5 - Button" DockPanel.Dock="Bottom" />
        <Button Content="6 - Button" DockPanel.Dock="Bottom" />

        <Button Content="7 - Button" DockPanel.Dock="Right" />
        <Button Content="8 - Button" DockPanel.Dock="Right" />
        <Button Content="9 - Button" DockPanel.Dock="Right" />
    </DockPanel>

#323 – Provide Space Around StackPanel Children Using Margin

By default, StackPanel provides no extra space around the child controls that it contains, but packs them tightly.

    <StackPanel>
        <Label Content="Gene Autry the singing cowboy" Background="Pink"/>
        <Button Content="I Like Gene" />
        <Label Content="Roy Rogers" Background="Aqua"/>
        <Button Content="I Like Roy Rogers Yes I Do"/>
        <Label Content="Spade Cooley had a sad story" Background="DodgerBlue"/>
    </StackPanel>


You can specify a margin that should be used around the outside of each control using the Margin property.

    <StackPanel>
        <Label Content="Gene Autry the singing cowboy" Background="Pink" Margin="5"/>
        <Button Content="I Like Gene" Margin="5"/>
        <Label Content="Roy Rogers" Background="Aqua" Margin="5"/>
        <Button Content="I Like Roy Rogers Yes I Do" Margin="5"/>
        <Label Content="Spade Cooley had a sad story" Background="DodgerBlue" Margin="5"/>
    </StackPanel>

In this example, we used a single value whenever we set the Margin property.  This causes the container to add the specified margin (in WPF units) along all four sides of the child control.