#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

#443 – Reversing the Flow Direction in a WrapPanel

You can set a WrapPanel to flow its children from right to left, rather then from left to right by setting the FlowDirection property to RightToLeft.  (The default is LeftToRight).

For a horizontally oriented WrapPanel, elements will fill in the top row from right to left, flowing to the second row when the first one fills up.  For a vertically oriented WrapPanel, elements will fill in the rightmost column from top to bottom and then move to the next column to the left when the first column fills up.

Below are examples of each combination of Orientation and FlowDirection.

Orientation = Horizontal, FlowDirection = LeftToRight (the default).

Orientation = HorizontalFlowDirection = RightToLeft.

Orientation = VerticalFlowDirection = LeftToRight (the default).

Orientation = VerticalFlowDirection = RightToLeft.

You would normally use right-to-left flow in culture that present text from right to left (e.g. Arabic).  But you can also use it whenever this layout makes sense for your application.

#442 – WrapPanel Child Elements Can Be Clipped

By default a WrapPanel will size it’s rows (in Horizontal orientation) or columns (in Vertical orientation) to the size of the tallest/widest element.  This means that no element is ever clipped due to row/column sizing, though they may be clipped if the WrapPanel itself has an explicit size specified.

Child elements can also be clipped if an element ends up larger than the specified ItemWidth and ItemHeight properties.  In the example below, ItemHeight has been set to 50, which is shorter than the Label that has three lines.

#441 – Setting a Consistent Height/Width for Child Elements in a WrapPanel

By default, child elements in a WrapPanel size to fit the largest item on a particular row or column (if their alignment is set to Stretch), or align themselves relative to the largest item on the row or column.

In the example below, the label with 3 lines makes the entire row larger.  But the second row is shorter because all of the labels in that row just have a single line.

You can make all of the child elements in a WrapPanel the same height by setting the WrapPanel’s ItemHeight property to some fixed value.

    <WrapPanel Orientation="Horizontal" ItemHeight="60">
        <Label Background="AliceBlue" Content="William I" VerticalAlignment="Center"/>
        <!-- etc -->

Now the child elements in the second row are the same height as the ones in the first row (and the labels are centered vertically in this larger space).

You can also set a consistent item width using the ItemWidth property.

#440 – How Alignment Properties Behave in a WrapPanel

The alignment properties, when specified for children of a WrapPanel, dictate the alignment within the current row (if Orientation is Horizontal) or column (if Orientation is Vertical).

For example, the VerticalAlignment properties of controls in a WrapPanel whose Orientation is Horizontal indicate the alignment of the control with respect to the other controls within the same row.

In the example below, the William II label is set artificially high, which then dictates the height of a row that it appears in.  Other controls on that same row will then align themselves relative to this height.

    <WrapPanel Orientation="Horizontal">
        <Label Background="AliceBlue" Content="William I" VerticalAlignment="Center"/>
        <Label Background="AntiqueWhite" Content="William II" VerticalAlignment="Center" Height="60"/>
        <Label Background="AliceBlue" Content="Henry I" VerticalAlignment="Bottom"/>
        <Label Background="AntiqueWhite" Content="Stephen" VerticalAlignment="Top"/>
        <Label Background="AliceBlue" Content="Matilda"  VerticalAlignment="Stretch"/>
        <Label Background="AntiqueWhite" Content="Henry II" VerticalAlignment="Center"/>
        <Label Background="AliceBlue" Content="Richard I" VerticalAlignment="Center"/>
        <Label Background="AntiqueWhite" Content="John" VerticalAlignment="Center"/>
    </WrapPanel>

#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.

#399 – WrapPanel Will Change Layout of its Children as its Size Changes

We saw that a WrapPanel will lay out its children either horizontally, filling a row at a time, or vertically, filling a column at a time.

The WrapPanel will also re-calculate the layout of its children whenever the size of the WrapPanel itself changes.  This will cause the location of the child elements to change.

Assume that we have the following WrapPanel whose Orientation property is set to Horizontal.  It lays out its child elements left to right on the first row and then starts a second row when the first row fills.

If we make the WrapPanel wider by making the Window wider, we can fit more child elements onto each row.

Similarly, if we make the WrapPanel narrower, we’ll fit fewer elements onto each row and so we’ll end up with more rows.

#398 – WrapPanel Element

The WrapPanel element serves as a container for a collection of child elements, positioning its children in one of two ways:

  • In a horizontal orientation (the default).  Child elements are added left to right, until a row fills up, and then wrapped to the next row
  • In a vertical orientation.  Child elements are added top to bottom, until a column fills up, and then wrapped to the next column
    <WrapPanel Orientation="Horizontal">
        <Label Background="AliceBlue" Content="William I" />
        <Label Background="AntiqueWhite" Content="William II"/>
        <!-- etc -->
    </WrapPanel>

    <WrapPanel Orientation="Vertical">
        <Label Background="AliceBlue" Content="William I" />
        <Label Background="AntiqueWhite" Content="William II"/>
        <!-- etc -->
    </WrapPanel>

Follow

Get every new post delivered to your Inbox.

Join 233 other followers