left-icon

Avalonia UI Succinctly®
by Alessandro Del Sole

Previous
Chapter

of
A
A
A

CHAPTER 4

Organizing the UI with Panels

Organizing the UI with Panels


One of the goals of XAML is simplifying the generation of dynamic user interfaces that automatically rearrange visual elements depending on page size and screen factors. Cross-platform development is even more important because phones, tablets, and laptops have different screen sizes and form factors. They also support both landscape and portrait orientations. Therefore, the user interface must dynamically adapt to the system, screen, and device so that visual elements can be automatically resized or rearranged based on the form factor and device orientation. In Avalonia UI, this is accomplished with panels, which is the topic of this chapter.

Understanding the concept of panels

Tip: If you have previous experience with WPF, UWP, or .NET MAUI, the concept of panels is something you already know.

One of the goals of Avalonia UI is providing the ability to create dynamic interfaces that can be rearranged according to the user’s preferences, or to the device and screen size. Because of this, controls in applications you build with Avalonia UI should not have a fixed size or position on the UI, except in a very limited number of scenarios. To make this possible, Avalonia UI controls are arranged within special containers, known as panels. Panels are classes that allow for arranging visual elements in the UI, and Avalonia UI provides many of them.

In this chapter, you’ll learn about available panels and how to use them to arrange controls. The most important thing to keep in mind is that controls in Avalonia UI have a hierarchical logic; therefore, you can nest multiple panels to create complex user experiences. Table 2 summarizes the available panels. You’ll learn about them in more detail in the sections that follow.

Table 2: Layouts in Avalonia UI

Layout

Description

StackPanel

Allows you to place visual elements near each other horizontally or vertically on a single line.

WrapPanel

Allows you to place visual elements near each other horizontally or vertically. Wraps visual elements to the next row or column if not enough space is available.

Grid

Allows you to organize visual elements within rows and columns.

Canvas

A panel placed at a specified, fixed position.

RelativePanel

A panel whose position depends on relative constraints.

ScrollViewer

Allows you to scroll the visual elements it contains.

DockPanel

Allows you to arrange visual elements relative to each other, either horizontally or vertically

Panel

Lays out all the children to fill the bounds of the panel itself. It works like a Grid with no rows and columns.

Remember that only one root panel is assigned to the Content property of a Window, and that panels can then contain nested visual elements and panels.

Tip: The Panel container will not be discussed, since its usage is less common and can be covered by talking about the Grid.

Alignment and spacing options

Panels can be aligned by assigning the HorizontalAlignment and VerticalAlignment properties with one of the property values from the HorizontalAlignment and VerticalAlignment enumerations, respectively. These are summarized in Table 3. Though not mandatory, providing an alignment option is very common.

Table 3: Alignment options in Avalonia UI

Alignment

Enumeration

Description

Center

VerticalAlignment

Aligns the visual element at the center, vertically

Top

VerticalAlignment

Aligns the visual element at the top

Bottom

VerticalAlignment

Aligns the visual element at the bottom

Stretch

VerticalAlignment

Expands the visual element’s bounds to fill the available space vertically

Center

HorizontalAlignment

Aligns the visual element at the center, horizontally

Right

HorizontalAlignment

Aligns the visual element at the right

Left

HorizontalAlignment

Aligns the visual element at the left

Stretch

HorizontalAlignment

Expands the visual element’s bounds to fill the available space horizontally

You can also control the space between visual elements with two properties: Spacing and Margin, summarized in Table 4.

Table 4: Spacing options in Avalonia UI

Spacing

Description

Margin

Represents the distance between the current visual element and its adjacent elements with either a fixed value for all four sides, or with comma-separated values for the left, top, right, and bottom. It is of type Thickness and XAML has a built-in type converter for it.

Spacing

Available only in the StackPanel container, it allows you to set the amount of space between each child element.

I recommend you spend some time experimenting with how alignment and spacing options work in order to understand how to get the appropriate result in your user interfaces.

The StackPanel

The StackPanel container allows the placing of controls near each other, as in a stack that can be arranged both horizontally and vertically. As with other containers, the StackPanel can contain nested panels. The following code shows how you can arrange controls horizontally and vertically. Code Listing 4 shows an example with a root StackPanel and two nested layouts.

Code Listing 4

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"

        x:Class="Ch4_Panels.StackPanelWindow"

        Title="StackPanelWindow">

       <StackPanel Orientation="Vertical">

              <StackPanel Orientation="Horizontal" Margin="5">

                     <TextBlock Text="Sample controls" Margin="5"/>

                     <Button Content="Test button" Margin="5"/>

              </StackPanel>

              <StackPanel Orientation="Vertical" Margin="5">

                     <TextBlock Text="Sample controls" Margin="5"/>

                     <Button Content="Test button" Margin="5"/>

              </StackPanel>

       </StackPanel>

</Window>

The result of the XAML in Code Listing 4 is shown in Figure 12.

Arranging visual elements with the StackPanel

Figure 12: Arranging visual elements with the StackPanel

The Orientation property can be set as Horizontal or Vertical, and this influences the final layout. If not specified, Vertical is the default. One of the main benefits of XAML code is that element names and properties are self-explanatory, and this is the case in StackPanel’s properties, too.

Remember that controls within a StackPanel are automatically resized according to the orientation. If you do not like this behavior, you need to specify Width and Height properties on each control, which represent the width and height, respectively.

Spacing is a property that you can use to adjust the amount of space between child elements; this is preferred to adjusting the space on the individual controls with the Margin property.

The WrapPanel

The WrapPanel works like a StackPanel, since it arranges child visual elements vertically or horizontally, but the difference is that it is also able to wrap the child visual elements if there is not enough space in a single row or column. Code Listing 5 provides an example and shows how easy it is to work with this layout.

Code Listing 5

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"

        x:Class="Ch4_Panels.WrapPanelWindow"

        Title="WrapPanelWindow">

       <WrapPanel>

              <WrapPanel Orientation="Horizontal" Margin="5">

                     <TextBlock Text="Sample controls" Margin="5"/>

                     <Button Content="Test button" Margin="5"/>

              </WrapPanel>

              <WrapPanel Orientation="Vertical" Margin="5">

                     <TextBlock Text="Sample controls" Margin="5"/>

                     <Button Content="Test button" Margin="5"/>

              </WrapPanel>

       </WrapPanel>

</Window>

Figure 13 shows a sample result for Code Listing 5 obtained by assigning the d:DesignWidth property of the Window with 200. By reducing the window’s width, the WrapPanel brings visual elements to the next row when necessary, making them still visible.

Arranging visual elements with the FlexLayout

Figure 13: Arranging visual elements with the FlexLayout

Remember that, like for the StackPanel, visual elements in a WrapPanel are aligned from left to right.

The Grid

The Grid is one of the easiest layouts to understand, and probably the most versatile. It allows you to create tables with rows and columns. In this way, you can define cells, and each cell can contain a control or another layout storing nested controls. The Grid is versatile in that you can just divide it into rows or columns, or both.

The following code defines a Grid that is divided into two rows and two columns:

<Grid>

   <Grid.RowDefinitions>

      <RowDefinition />

      <RowDefinition />

   </Grid.RowDefinitions>

   <Grid.ColumnDefinitions>

      <ColumnDefinition />

      <ColumnDefinition />

   </Grid.ColumnDefinitions>

</Grid>

RowDefinitions is a collection of RowDefinition objects, and the same is true for ColumnDefinitions and ColumnDefinition. Each item represents a row or a column within the Grid, respectively. You can also specify a Width or a Height property to delimit row and column dimensions; if you do not specify anything, both rows and columns are dimensioned at the maximum size available. When resizing the parent container, rows and columns are automatically rearranged.

The preceding code creates a table with four cells. To place controls in the Grid, specify the row and column position via the Grid.Row and Grid.Column properties, known as attached properties, on the control.

Note: The Avalonia UI documentation explains how to create and consume new attached properties, but if you want to discover more about this topic, I recommend that you have a look at the WPF documentation.

Attached properties allow for assigning properties of the parent container from the current visual element. The index of both is zero-based, meaning that 0 represents the first column from the left and the first row from the top. You can place nested layouts within a cell or a single row or column. The code in Code Listing 6 shows how to nest a grid into a root grid with child controls.

Tip: Grid.Row="0" and Grid.Column="0" can be omitted.

Code Listing 6

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"

        x:Class="Ch4_Panels.GridPanelWindow"

        Title="GridPanelWindow">

       <Grid>

              <Grid.RowDefinitions>

                     <RowDefinition />

                     <RowDefinition />

              </Grid.RowDefinitions>

              <Grid.ColumnDefinitions>

                     <ColumnDefinition />

                     <ColumnDefinition />

              </Grid.ColumnDefinitions>

              <Button Content="First Button" />

              <Button Grid.Column="1" 

                            Content="Second Button"/>

 

              <Grid Grid.Row="1">

                     <Grid.RowDefinitions>

                            <RowDefinition />

                            <RowDefinition />

                     </Grid.RowDefinitions>

                     <Grid.ColumnDefinitions>

                            <ColumnDefinition />

                            <ColumnDefinition />

                     </Grid.ColumnDefinitions>

                     <Button Content="Button 3" />

                     <Button Content="Button 4" Grid.Column="1" />

              </Grid>

       </Grid>

</Window>

Figure 14 shows the result of this code.

Arranging visual elements with the Grid

Figure 14: Arranging visual elements with the Grid

The Grid layout is very versatile and is also a good choice (when possible) in terms of performance.

Spacing and proportions for rows and columns

You have fine-grained control over the size, space, and proportions of rows and columns. The Height and Width properties of the RowDefinition and ColumnDefinition objects can be set with values from the GridUnitType enumeration as follows:

·     Auto: Automatically sizes to fit content in the row or column.

·     Star: Sizes columns and rows as a proportion of the remaining space.

·     Absolute: Sizes columns and rows with specific, fixed height and width values.

XAML has type converters for the GridUnitType values, so you simply pass no value for Auto, a * for Star, and the fixed numeric value for Absolute, such as:

<Grid.ColumnDefinitions>

   <ColumnDefinition />

   <ColumnDefinition Width="*"/>

   <ColumnDefinition Width="20"/>

</Grid.ColumnDefinitions>

If you wish, you can also explicitly pass Width="Auto" instead of passing no value.

Introducing spans

In some situations, you might have elements that should occupy more than one row or column. In these cases, you can assign the Grid.RowSpan and Grid.ColumnSpan attached properties with the number of rows and columns a visual element should occupy.

The Canvas

Sometimes you might need to place controls on the UI in a fixed position, regardless of the dynamic rearrangement. In these cases, you can use the Canvas panel, which allows for the so-called absolute positioning of its child elements, which are placed via the Canvas.Top, Canvas.Left, Canvas.Bottom, and Canvas.Right attached properties. These represent the distance from the upper margin, the distance from the left margin, the distance from the lower margin, and the distance from the right margin. They must be used in couples: Canvas.Top with Canvas.Left, and Canvas.Bottom with Canvas.Right. Other combinations are not valid. Consider the following code snippet:

<Canvas>

     <TextBlock Text="This text will never change position"

         Canvas.Left="50" Canvas.Top="30"/>

</Canvas>

The TextBlock control is positioned 50 pixels from the left edge, and 30 pixels from the top edge of the canvas. If you run the code, you will notice that the position of the control will never be rearranged as the interface changes.

Tip: The Canvas child elements are spaced from the canvas itself, and not from the window. This means that if the Canvas.Margin property is assigned or if the Canvas is contained in a StackPanel or WrapPanel, the location will be evaluated based on the organization of those panels. For this reason, the Canvas should be the root panel within a Window or UserControl.

The RelativePanel

The RelativePanel allows you to arrange elements by specifying their relative positioning with respect to other elements and the panel itself. By default, elements are positioned at the upper-left corner of the panel. You use some attached properties to govern the layout of these elements. Table 5 summarizes these properties.

Table 5: Attached properties to control the RelativePanel

Panel alignment

Relative alignment

Relative Position

AlignTopWithPanel

AlignTopWith

Above

AlignBottomWithPanel

AlignBottomWith

Below

AlignLeftWithPanel

AlignLeftWith

LeftOf

AlignRightWithPanel

AlignRightWith

RightOf

AlignHorizontalCenterWithPanel

AlignHorizontalCenterWith

AlignVerticalCenterWithPanel

AlignVerticalCenterWith

The attached properties listed in the Panel Alignment column of Table 5 are of type bool and determine the way the child element is aligned with respect to the panel. The attached properties listed in the Relative Alignment column of Table 5 take the name of a relative control as value, and specify the alignment. Attached properties listed in the Relative Position column specify the position of the child element and take the name of the relative control as the value. Code Listing 7 provides an example of RelativePanel.

Code Listing 7

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"

        x:Class="Ch4_Panels.RelativePanelWindow"

        Title="RelativePanelWindow">

       <RelativePanel Background="Gray">

              <Rectangle x:Name="OrangeRectangle" Fill="Orange" Height="44" 

                  Width="44"/>

              <Rectangle x:Name="RedRectangleangle" Fill="Green"

                               Height="44" Width="88"

                        RelativePanel.RightOf="OrangeRectangle" />

 

              <Rectangle x:Name="RedRectangle" Fill="Red"

                               Height="44"

                               RelativePanel.Below="OrangeRectangle"

                        RelativePanel.AlignLeftWith="OrangeRectangle"                      RelativePanel.AlignRightWith="RedRectangleangle"/>

              <Rectangle Fill="Blue"

                               RelativePanel.Below="RedRectangle"

                        RelativePanel.AlignLeftWith="RedRectangleangle"

                               RelativePanel.AlignRightWithPanel="True"

                               RelativePanel.AlignBottomWithPanel="True"/>

       </RelativePanel>

</Window>

The example is based on some Rectangle elements, which are an appropriate choice due to the fact they can fill colored areas on screen, and make it easier to understand their relative positioning. As you can see, the attached properties listed in Table 5 allow for specifying the position of each rectangle, with respect to the panel and the other rectangles. Figure 15 shows the result of Code Listing 7.

Arranging visual elements within a RelativePanel

Figure 15: Arranging visual elements within a RelativePanel

The ScrollViewer

The ScrollViewer allows you to present content that cannot fit on one screen, and therefore should be scrolled. Technically speaking, this is considered a control, but actually you use it as a panel. Its usage is very simple and is demonstrated in Code Listing 8.

Code Listing 8

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"

       Height="500"

        x:Class="Ch4_Panels.ScrollViewerWindow"

        Title="ScrollViewerWindow">

       <ScrollViewer Name="Scroll1">

              <StackPanel

                      <TextBlock Text="My favorite color:" 

                                  Name="TextBlock1"/>

                     <Rectangle Height="600" Fill="BlueViolet"/>

              </StackPanel>

       </ScrollViewer>

</Window>

You basically add a panel or visual element inside the ScrollViewer and, at runtime, the content will be scrollable if its area is bigger than the screen size. You can also decide whether to display the scroll bars through the HorizontalScrollbarVisibility and VerticalScrollbarVisibility properties that can be assigned with self-explanatory values such as Visible, Disable, and Hidden.

Notice how, in order to simulate content that is longer than the actual screen size, a Height of 500 has been assigned to the Window, whereas a Height of 600 has been assigned to the rectangle. Remember to avoid nesting ScrollViewer views and to include controls like DataGrid and ListBox inside a ScrollViewer, since these include their own scrolling mechanism.

The DockPanel

The DockPanel container also has many similarities to the StackPanel, because it allows you to tile the controls it contains. The main difference is that child controls are docked to the sides of the DockPanel in the specified direction, they are also docked to each other, and their size and position can be specified. The typical use of the DockPanel is therefore related to the creation of interfaces in which menus and toolbars are connected to one another. The XAML in Code Listing 9 shows how to create a DockPanel and how to add a menu bar and a status bar, docked to each other:

Code Listing 9

<Window xmlns="https://github.com/avaloniaui"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"

        x:Class="Ch4_Panels.DockPanelWindow"

        Title="DockPanelWindow">

       <DockPanel LastChildFill="True"

                        VerticalAlignment="Top">

              <Menu DockPanel.Dock="Top"

                       Background="LightGray"

             Name="MainMenu" >

                     <MenuItem Header="File"/>

                     <MenuItem Header="Edit"/>

              </Menu>

 

              <StackPanel DockPanel.Dock="Top">

                     <TextBlock Text="Command bar" />

              </StackPanel>

       </DockPanel>

</Window>

The result of the code is shown in Figure 16.

Arranging visual elements within a DockPanel

Figure 16: Arranging visual elements within a DockPanel

The orientation of the controls contained in the DockPanel is set through the VerticalAlignment property, whose values ​​can be Top, Bottom, Center, or Stretch (to fill the available space). Through the LastChildFill property, the container is told whether the controls it contains should fill all the available space. The example assigns True, but you can set to False to tell the difference.

Finally, by assigning the DockPanel.Dock attached property, it is possible to establish the position in which the controls must be docked within the DockPanel.

Chapter summary

Modern apps require dynamic user interfaces that can automatically adapt to the screen size of different device form factors. In Avalonia UI, creating dynamic user interfaces is possible through a number of panels.

The StackPanel allows you to arrange controls near one another both horizontally and vertically. The WrapPanel does the same, but it is also capable of wrapping visual elements. The Grid allows you to arrange controls within rows and columns; the Canvas allows you to give controls an absolute position; the RelativePanel allows you to arrange controls based on the size and position of other controls or containers; the ScrollViewer allows you to scroll the content of visual elements that do not fit in a single page; and the DockPanel allows you to dock child elements to the specified edge.

Now that you have a basic knowledge of panels, it’s time to discuss common controls in Avalonia UI that allow you to build the functionalities of the user interface, arranged within the panels you learned in this chapter.


Scroll To Top
Disclaimer

DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.