User Tools

Site Tools


notes:uwp:layout

Layout in XAML

Canvas

Canvas is the most lightweight of the layout containers. It provides the following attached properties for its children:

  • Canvas.Left
  • Canvas.Top
  • Canvas.ZIndex (default is 0)

Example:

<Canvas Width="120" Height="120">
    <Rectangle Fill="Red" Height="44" Width="44" Canvas.ZIndex="1"/>
    <Rectangle Fill="Blue" Height="44" Width="44" Canvas.Left="20" Canvas.Top="20"/>
    <Rectangle Fill="Green" Height="44" Width="44" Canvas.Left="40" Canvas.Top="40"/>
    <Rectangle Fill="Yellow" Height="44" Width="44" Canvas.Left="60" Canvas.Top="60"/>
</Canvas>

Grid

  • The default value of the Grid's HorizontalAlignment and VerticalAlignment is Stretch which means that the Grid covers all available space by default.
  • The ActualHeight property of RowDefinition and the ActualWidth property of ColumnDefinition contain actual sizes of the row and the column.
  • The Height property of RowDefinition and the Width property of ColumnDefinition are both of type GridLength.
  • The default column width is “*”.

The size of each column in the Grid can be defined in one of three ways:

  • Fixed sizing - If the column is too narrow the content is cropped. Units are logical pixels.
  • Automatic sizing - Makes the column wide enough to contain the widest element.
  • Proportional sizing (default) - Fills out the remaining space after fixed and automatic items are positioned. If there are multiple “*” items, the space is shared evenly between them. You can apply a weight to columns by placing a coefficient in front of the *.

The above sizing methods also apply to rows and the height of the rows.

Example: Mixing proportional and fixed sizing:

<Grid Width="400" Margin="100">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="40" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
        <ColumnDefinition Width="2*" />
    </Grid.ColumnDefinitions>
 
    <Rectangle Grid.Column="0" Fill="Blue" />
    <Rectangle Grid.Column="1" Fill="Red" Width="60" />
    <Rectangle Grid.Column="2" Fill="Yellow" />
    <Rectangle Grid.Column="3" Fill="Green" />
</Grid>
Column Width Remarks
Column_0 40 The column is 40 pixels wide.
Column_1 Auto The column adjusts its size to fit its content - a 60-pixel wide rectangle.
Column_2 * After the Auto columns are calculated, the column gets part of the remaining width. Column_2 is one-half as wide as Column_3.
Column_3 2* After the Auto columns are calculated, the column gets part of the remaining width. Column_3 is twice as wide as Column_2.

Example: Change the size of the Grid's columns programmatically:

<Grid Loaded="Grid_Loaded">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="Column1" />
        <ColumnDefinition x:Name="Column2" />
        <ColumnDefinition x:Name="Column3" />
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" x:Name="TextBlock1" Text="Testing1" />
    <TextBlock Grid.Column="1" x:Name="TextBlock2" Text="Testing2" />
</Grid>
private void Grid_Loaded(object sender, RoutedEventArgs args)
{
    // Set the width of the first column to a specific size.
    Column1.Width = new GridLength(16);
 
    // Set the width of the second column to Auto.
    Column2.Width = GridLength.Auto;
 
    // Set the width of the third column to Star.
    Column3.Width = new GridLength(1, GridUnitType.Star);
 
    // Check what column TextBlock1 is in.
    Debug.WriteLine(TextBlock1.GetValue(Grid.ColumnProperty)); // 0
 
    // Swap assignment of columns in TextBoxes.
    Grid.SetColumn(TextBlock1, 1);
    Grid.SetColumn(TextBlock2, 0);
 
    // Check what column TextBlock1 is in.
    Debug.WriteLine(TextBlock1.GetValue(Grid.ColumnProperty)); // 1
}

Example: Create a Grid that looks like a WPF DockPanel:

<Grid Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
 
    <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Background="Red">
        <TextBlock Padding="20">Top</TextBlock>
    </StackPanel>
    <StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Background="Magenta">
        <TextBlock Padding="20">Bottom</TextBlock>
    </StackPanel>
 
    <StackPanel Grid.Row="1" Grid.Column="0" Background="Gray">
        <TextBlock Padding="20">Left</TextBlock>
    </StackPanel>
    <StackPanel Grid.Row="1" Grid.Column="2" Background="Cyan">
        <TextBlock Padding="20">Right</TextBlock>
    </StackPanel>
 
    <TextBlock Grid.Row="1" Grid.Column="1" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center">Content</TextBlock>
</Grid>

Example: In the following code snippet, the * is turned into Auto because the StackPanel offers to the Grid an infinite height:

<StackPanel Orientation="Vertical" Background="AliceBlue">
    <Grid Margin="20" Background="Blue">
        <Grid.RowDefinitions>
            <RowDefinition Height="60" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="Header" FontSize="45" Foreground="White" />
        <TextBlock Grid.Row="1" Text="Some text here..."  Foreground="White" />
    </Grid>
</StackPanel>

Hub

A Hub control with two sections and a background:

<Hub Header="Main Header">
    <Hub.Background>
        <ImageBrush ImageSource="/Assets/BackgroundImage.jpg" />
    </Hub.Background>
    <HubSection Header="Section Header1" Width="400">
        <DataTemplate>
            <TextBlock Text="Section1" />
        </DataTemplate>
    </HubSection>
    <HubSection Header="Section Header2" MinWidth="200">
        <DataTemplate>
            <TextBlock Text="Section2" />
        </DataTemplate>
    </HubSection>
</Hub>

You can use just a HubSection element to layout controls:

<HubSection Header="Section Header" Width="200">
    <DataTemplate>
        <ItemsControl>
            <x:String>One</x:String>
            <x:String>Two</x:String>
            <x:String>Three</x:String>
        </ItemsControl>
    </DataTemplate>
</HubSection>

The Hub element may have a SectionHeaderClick event handler specified. In order for a HubSection to raise the SectionHeaderClick event, the HubSection's IsHeaderInteractive property has to be set to True.

<Hub Header="Main Header" SectionHeaderClick="Hub_SectionHeaderClick">
    <!-- this section raises the SectionHeaderClick event -->
    <HubSection Header="Section Header1" IsHeaderInteractive="True">
        <DataTemplate>
            <TextBlock Text="Section1" />
        </DataTemplate>
    </HubSection>
    <!-- this section does not raise the SectionHeaderClick event -->
    <HubSection Header="Section Header2">
        <DataTemplate>
            <TextBlock Text="Section2" />
        </DataTemplate>
    </HubSection>
</Hub>
private void Hub_SectionHeaderClick(object sender, HubSectionHeaderClickEventArgs args)
{
    HubSection section = args.Section;
}

An example of a layout using a Hub control:

<Page x:Class="TestApp.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.Background>
            <ImageBrush ImageSource="/Assets/MountainLake.jpg" />
        </Grid.Background>
 
        <Hub>
            <Hub.Header>
                <TextBlock Text="Mountains and Lakes" Foreground="White" />
            </Hub.Header>
            <HubSection Width="500">
                <HubSection.Header>
                    <TextBlock Text="Introduction" Foreground="White" />
                </HubSection.Header>
                <DataTemplate>
                    <Grid>
                        <TextBlock Text="Lorem ipsum dolores..." Foreground="White" />
                    </Grid>
                </DataTemplate>
            </HubSection>
            <HubSection Background="#55222222" Foreground="White" MinWidth="250">
                <HubSection.Header>
                    <TextBlock Text="Somewhere" Foreground="White" />
                </HubSection.Header>
                <DataTemplate>
                    <GridView>
                        <GridView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <ItemsWrapGrid Orientation="Vertical" />
                            </ItemsPanelTemplate>
                        </GridView.ItemsPanel>
                        <GridView.ItemTemplate>
                            <DataTemplate>
                                <Border Height="250" Width="250">
                                    <Border.Background>
                                        <SolidColorBrush Color="White" Opacity="0.5" />
                                    </Border.Background>
                                    <StackPanel VerticalAlignment="Bottom">
                                        <StackPanel.Background>
                                            <SolidColorBrush Color="Black" Opacity="0.6" />
                                        </StackPanel.Background>
                                        <TextBlock Margin="12" Foreground="White" 
                                                   FontSize="20" Text="{Binding}" />
                                    </StackPanel>
                                </Border>
                            </DataTemplate>
                        </GridView.ItemTemplate>
                        <x:String>Lake #1</x:String>
                        <x:String>Lake #2</x:String>
                        <x:String>Lake #3</x:String>
                        <x:String>Lake #4</x:String>
                        <x:String>Lake #5</x:String>
                        <x:String>Lake #6</x:String>
                        <x:String>Lake #7</x:String>
                    </GridView>
                </DataTemplate>
            </HubSection>
            <HubSection Background="#55444444" Foreground="White" MinWidth="300">
                <HubSection.Header>
                    <TextBlock Text="Summary" Foreground="White" />
                </HubSection.Header>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="Lorem pumpitsu butorem..." />
                    </StackPanel>
                </DataTemplate>
            </HubSection>
        </Hub>
    </Grid>
</Page>

Pivot

Example:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Pivot Title="Pivot Title">
        <PivotItem Header="Pivot Item 1">
            <TextBlock Text="Content of pivot item 1."/>
        </PivotItem>
        <PivotItem Header="Pivot Item 2">
            <TextBlock Text="Content of pivot item 2."/>
        </PivotItem>
        <PivotItem Header="Pivot Item 3">
            <TextBlock Text="Content of pivot item 3."/>
        </PivotItem>
    </Pivot>
</Grid>

Example: Navigate to the first PivotItem in a Pivot control:

private void Pivot_Loaded(object sender, RoutedEventArgs args)
{
    Pivot pivo = sender as Pivot;
    pivo.SelectedItem = pivo.Items[0];
}

RelativePanel

Use RelativePanel to specify a position of a element in relation to other elements and in relation to the panel. By default, an element is positioned in the upper left corner of the panel. You can use RelativePanel with a VisualStateManager and AdaptiveTriggers to rearrange your UI for different window sizes.

These are attached properties to align an element with the edge or center of the panel, and align and position it in relation to other elements:

Panel alignment Sibling alignment Sibling position
AlignTopWithPanel AlignTopWith Above
AlignBottomWithPanel AlignBottomWith Below
AlignLeftWithPanel AlignLeftWith LeftOf
AlignRightWithPanel AlignRightWith RightOf
AlignHorizontalCenterWithPanel AlignHorizontalCenterWith
AlignVerticalCenterWithPanel AlignVerticalCenterWith

Example:

<RelativePanel BorderBrush="Gray" BorderThickness="10">
    <Rectangle x:Name="RedRect" Fill="Red" MinHeight="100" MinWidth="100"/>
    <Rectangle x:Name="BlueRect" Fill="Blue" MinHeight="100" MinWidth="100" 
        RelativePanel.RightOf="RedRect"/>
    <!-- Width is not set on the green and yellow rectangles.
         It's determined by the RelativePanel properties. -->
    <Rectangle x:Name="GreenRect" Fill="Green" MinHeight="100" Margin="0,5,0,0" 
        RelativePanel.Below="RedRect" 
        RelativePanel.AlignLeftWith="RedRect" 
        RelativePanel.AlignRightWith="BlueRect"/>
    <Rectangle Fill="Yellow" MinHeight="100" 
        RelativePanel.Below="GreenRect" 
        RelativePanel.AlignLeftWith="BlueRect" 
        RelativePanel.AlignRightWithPanel="True"/>
</RelativePanel>

Example: RelativePanel vs. StackPanel. Both of the following code snippets generate the same output:

<!-- StackPanel -->
<StackPanel Orientation="Horizontal" Margin="100" >
    <StackPanel>
        <Button Content="1" />
        <Button Content="2" />
        <Button Content="3" />
    </StackPanel>
    <StackPanel>
        <Button Content="4" />
        <Button Content="5" />
        <Button Content="6" />
    </StackPanel>
</StackPanel>
 
<!-- RelativePanel -->
<RelativePanel>
    <StackPanel x:Name="LeftColumn" >
        <Button Content="1" />
        <Button Content="2" />
        <Button Content="3" />
    </StackPanel>
    <StackPanel RelativePanel.RightOf="LeftColumn">
        <Button Content="4" />
        <Button Content="5" />
        <Button Content="6" />
    </StackPanel>
</RelativePanel>

Example: Change the position of an element in a RelativePanel programmatically:

<RelativePanel Margin="100">
    <StackPanel x:Name="LeftColumn" >
        <Button Content="1" />
        <Button Content="2" />
        <Button Content="3" />
    </StackPanel>
    <StackPanel x:Name="RightColumn" RelativePanel.RightOf="LeftColumn">
        <Button Content="4" />
        <Button Content="5" />
        <Button Content="6" />
    </StackPanel>
</RelativePanel>
// Move the RightColumn StackPanel below the LeftColumn. 
RightColumn.SetValue(RelativePanel.BelowProperty, LeftColumn);
RightColumn.SetValue(RelativePanel.AlignLeftWithPanelProperty, true);
RightColumn.SetValue(RelativePanel.AlignRightWithPanelProperty, true);

SplitView

Use SplitView to show and hide transient content. SplitView is commonly used for top-level navigation like the “hamburger menu”, where the navigation content is hidden, and slides in when needed.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <SplitView x:Name="SplitView1" 
               IsPaneOpen="True"
               DisplayMode="Overlay"
               OpenPaneLength="296"
               PanePlacement="Right"
               PaneBackground="Navy">
        <SplitView.Pane>
            <StackPanel>
                <TextBlock Text="Pane"
                           FontSize="24"
                           VerticalAlignment="Center"
                           HorizontalAlignment="Center"/>
                <TextBox Width="250" />
            </StackPanel>
        </SplitView.Pane>
 
        <Grid>
            <TextBlock Text="Content"
                       FontSize="24"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"/>
            <!-- the show/hide button is usually implemented as a "hamburger menu" button -->
            <Button Content="Show/Hide Pane" 
                    Click="Button_Click" 
                    HorizontalAlignment="Center" 
                    Margin="0,100,0,0" />
        </Grid>
    </SplitView>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
    SplitView1.IsPaneOpen = !SplitView1.IsPaneOpen;
}

StackPanel

By default the StackPanel's HorizontalAlignment and VerticalAlignment properties are set to Stretch:

<Grid Background="Azure">
    <StackPanel Background="Wheat">
        <TextBlock Text="text" Margin="4" />
        <TextBlock Text="more text" Margin="4" />
        <TextBlock Text="even more text" Margin="4" />
    </StackPanel>
</Grid>

By setting values other than Stretch, the StackPanel can be made large enough to fit the widest (or the tallest) element.

When you align the StackPanel to the left, it becomes large enough to fit the widest element:

<Grid Background="Azure">
    <StackPanel Background="Wheat" HorizontalAlignment="Left">
        <TextBlock Text="text" Margin="4" />
        <TextBlock Text="more text" Margin="4" />
        <TextBlock Text="even more text" Margin="4" />
    </StackPanel>
</Grid>

Similarily, when you align the StackPanel to the right, it becomes large enough to fit the widest element:

<Grid Background="Azure">
    <StackPanel Background="Wheat" HorizontalAlignment="Right">
        <TextBlock Text="text" Margin="4" />
        <TextBlock Text="more text" Margin="4" />
        <TextBlock Text="even more text" Margin="4" />
    </StackPanel>
</Grid>

StackPanel does not have scrolling capability. Wrap the StackPanel into a ScrollViewer. Otherwise, if the content of the StackPanel does not fit on the screen, it will extend out of the screen. In other words: StackPanel provides infinite space for its children i.e. it grows as there are more children.

<ScrollViewer HorizontalAlignment="Center">
    <StackPanel>
        ...
    </StackPanel>
</ScrollViewer>

In a StackPanel, if a child element's size is not set explicitly, it stretches to fill the available width (or height if the Orientation is Horizontal):

<StackPanel Background="Wheat">
    <Rectangle Fill="Green" Height="50" />
</StackPanel>

Example: Dock buttons to the right-bottom corner using the StackPanel's alignment properties:

<Page x:Class="TestApp.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:TestApp">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
 
        <TextBlock Text="First Name" VerticalAlignment="Center" Margin="8" />
        <TextBox Grid.Column="1" Margin="8" />
 
        <TextBlock Grid.Row="1" Text="Last Name" VerticalAlignment="Center" Margin="8" />
        <TextBox Grid.Row="1" Grid.Column="1" Margin="8" />
 
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Right"
                    VerticalAlignment="Bottom"
                    Grid.Row="2" 
                    Grid.ColumnSpan="2">
            <Button Content="Save" Width="80" Margin="8" />
            <Button Content="Cancel" Width="80" Margin="8" />
        </StackPanel>
    </Grid>
</Page>

VariableSizedWrapGrid

<VariableSizedWrapGrid Orientation="Vertical"
                       ItemWidth="100" ItemHeight="100"
                       MaximumRowsOrColumns="2">
    <Rectangle Fill="Blue" Width="100" Height="100" />
    <Rectangle Fill="Green" Height="100" VariableSizedWrapGrid.ColumnSpan="2" />
    <Rectangle Fill="Red" Width="100" Height="100" />
    <Rectangle Fill="Orange" Width="100" VariableSizedWrapGrid.RowSpan="2" />
</VariableSizedWrapGrid>

UseLayoutRounding

Example: Set the UseLayoutRounding property to true on your layout container to ensure that all the content in the layout container is snapped to the nearest pixel boundary:

<Grid UseLayoutRounding="True">
...
</Grid>
notes/uwp/layout.txt · Last modified: 2017/02/28 by admin