left-icon

.NET MAUI Succinctly®
by Alessandro Del Sole

Previous
Chapter

of
A
A
A

CHAPTER 4

Organizing the UI with Layouts

Organizing the UI with Layouts


Mobile devices such as phones, tablets, and laptops have different screen sizes and form factors. They also support both landscape and portrait orientations. Therefore, the user interface in mobile apps 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 .NET MAUI, this is accomplished with layouts, which is the topic of this chapter.

Understanding the concept of layout

Tip: If you have previous experience with Xamarin.Forms, you will find a lot of similarities with layout in MAUI. If you do not have experience with Xamarin.Forms but you have worked with WPF or UWP, the concept of layout is the same as the concept of panels, such as the Grid and the StackPanel.

One of the goals of .NET MAUI is to provide 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 mobile apps you build with MAUI should not have a fixed size or position in the UI, except in a very limited number of scenarios. To make this possible, controls are arranged within special containers, known as layouts. Layouts are classes that allow for arranging visual elements in the UI, and MAUI provides many of them.

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

Note: The documentation also includes StackLayout in the list of supported layouts, but at the same time, it recommends that you not use it in favor of the VerticalStackLayout and HorizontalStackLayout views. The StackLayout has been kept for making the migration from Xamarin.Forms easier, but it should not be used, and this is why it is not discussed here.

Table 1: Layouts in .NET MAUI

Layout

Description

VerticalStackLayout

Allows you to place visual elements near each other vertically.

HorizontalStackLayout

Allows you to place visual elements near each other horizontally.

FlexLayout

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.

AbsoluteLayout

A layout placed at a specified, fixed position.

ScrollView

Allows you to scroll the visual elements it contains.

Frame

Draws a border and adds space around the visual element it contains.

TwoPaneView

Provides support for foldable devices.

Remember that only one root layout is assigned to the Content property of a page, and that layout can then contain nested visual elements and layouts. The Content property can also be implicit in XAML, which means that the <Content> </Content> tags can be omitted.

Note: Technically speaking, the Frame is a control rather than a layout, but you do not use it individually. Instead, you use it as a container of other visual elements.

Alignment and spacing options

As a general rule, both layouts and controls can be aligned by assigning the HorizontalOptions and VerticalOptions properties with one of the property values from the LayoutOptions structure, summarized in Table 2.

Providing an alignment option is very common. For instance, if you only have the root layout in a page, you will want to assign VerticalOptions with StartAndExpand so that the layout gets all the available space in the page (remember this consideration when you experiment with layouts and views in this chapter and the next one).

Table 2: Alignment Options in .NET MAUI

Alignment

Description

Center

Aligns the visual element at the center.

Start

Aligns the visual element at the left.

End

Aligns the visual element at the right.

Fill

Makes the visual element have no padding around itself, and it does not expand.

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

Table 3: Spacing Options in .NET MAUI

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 built in a type converter for it.

Padding

Represents the distance between a visual element and its child elements. It can be set 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 built in a type converter for it.

Spacing

Available only in the StackLayout container, it allows you to set the amount of space between each child element, with a default of 6.0.

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

The VerticalStackLayout and HorizontalStackLayout

Both the VerticalStackLayout and HorizontalStackLayout containers allow for placing visual elements near each other as in a stack. The difference is in the orientation as their names imply. Code Listing 5 shows how to arrange visual elements with these containers.

Code Listing 5

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="App1.MainPage">

 

    <VerticalStackLayout>

        <HorizontalStackLayout Margin="5">

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

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

        </HorizontalStackLayout>

        <HorizontalStackLayout Margin="5">

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

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

        </HorizontalStackLayout>

    </VerticalStackLayout>

</ContentPage>

Remember that controls within a HorizontalStackLayout and VerticalStackLayout are automatically resized according to the orientation. If you do not like this behavior, you need to specify WidthRequest and HeightRequest 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. Figure 23 shows the result of Code Listing 5.

Arranging visual elements with the VerticalStackLayout and HorizontalStackLayout

Figure 23: Arranging visual elements with the VerticalStackLayout and HorizontalStackLayout

The FlexLayout

The FlexLayout works like a StackLayout since it arranges child visual elements vertically or horizontally; 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 6 provides an example and shows how easy it is to work with this layout.

Code Listing 6

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="App1.MainPage">

 

        <FlexLayout Wrap="Wrap" JustifyContent="SpaceAround"

                   Direction="Row">

            <Label Text="This is a sample label in a page"

                  FlexLayout.AlignSelf="Center"/>

            <Button Text="Tap here to get things done"

                   FlexLayout.AlignSelf="Center" x:Name="Button1"/>

        </FlexLayout>

</ContentPage>

The FlexLayout exposes several properties, most of them common to other layouts, but the following are exclusive to FlexLayout, and certainly are the most important to use to adjust its behavior:

·     Wrap: A value from the FlexWrap enumeration that specifies if the FlexLayout content should be wrapped to the next row if there is not enough space in the first one. Possible values are Wrap (wraps to the next row), NoWrap (keeps the view content on one row), and Reverse (wraps to the next row in the opposite direction).

·     Direction: A value from the FlexDirection enumeration that determines if the children of the FlexLayout should be arranged in a single row or column. The default value is Row. Other possible values are Column, RowReverse, and ColumnReverse (where Reverse means that child views will be laid out in the reverse order).

·     JustifyContent: A value from the FlexJustify enumeration that specifies how child views should be arranged when there is extra space around them. There are self-explanatory values such as Start, Center, and End, as well other options such as SpaceAround, where elements are spaced with one unit of space at the beginning and end, and two units of space between them, so the elements and the space fill the line; and SpaceBetween, where child elements are spaced with equal space between units and no space at either end of the line, again so the elements and the space fill the line. The SpaceEvenly value causes child elements to be spaced so the same amount of space is set between each element as there is from the edges of the parent to the beginning and end elements.

You can specify the alignment of child views in the FlexLayout by assigning the FlexLayout.AlignSelf attached property with self-explanatory values such as Start, Center, End, and Stretch. For a quick understanding, you can take a look at Figure 24, which demonstrates how child views have been wrapped.

Arranging visual elements with the FlexLayout

Figure 24: Arranging visual elements with the FlexLayout

If you change the Wrap property value to NoWrap, child views will be aligned on the same row, overlapping each other. The FlexLayout is therefore particularly useful to create dynamic hierarchies of visual elements, especially when you do not know the size of child elements in advance.

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 divide it into just 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, you specify the row and column position via the Grid.Row and Grid.Column properties, known as attached properties, on the control. 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 7 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 7

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

            x:Class="Layouts.GridSample">

    <ContentPage.Content>

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition />

                <RowDefinition />

            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>

                <ColumnDefinition />

                <ColumnDefinition />

            </Grid.ColumnDefinitions>

            <Button Text="First Button" Margin="5"/>

            <Button Grid.Column="1" Text="Second Button" Margin="5"/>

            <Grid Grid.Row="1" Margin="10">

                <Grid.RowDefinitions>

                    <RowDefinition />

                    <RowDefinition />

                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>

                    <ColumnDefinition />

                    <ColumnDefinition />

                </Grid.ColumnDefinitions>

                <Button Text="Button 3" Margin="5"/>

                <Button Text="Button 4" Margin="5" Grid.Column="1" />

            </Grid>

        </Grid>

    </ContentPage.Content>

</ContentPage>

Figure 25 shows the result of this code.

Arranging visual elements with the Grid

Figure 25: Arranging visual elements with the Grid

The Grid layout is very versatile and 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 as follows:

<Grid.ColumnDefinitions>

   <ColumnDefinition />

   <ColumnDefinition Width="*"/>

   <ColumnDefinition Width="20"/>

</Grid.ColumnDefinitions>

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 AbsoluteLayout

The AbsoluteLayout container allows you to specify where exactly on the screen you want the child elements to appear, as well as their sizes and bounds. There are a few different ways to set the bounds of the child elements based on the AbsoluteLayoutFlags enumeration used during this process.

The AbsoluteLayoutFlags enumeration contains the following values:

·     All: All dimensions are proportional.

·     HeightProportional: Height is proportional to the layout.

·     None: No interpretation is done.

·     PositionProportional: Combines XProportional and YProportional.

·     SizeProportional: Combines WidthProportional and HeightProportional.

·     WidthProportional: Width is proportional to the layout.

·     XProportional: X property is proportional to the layout.

·     YProportional: Y property is proportional to the layout.

Once you have created your child elements, to set them at an absolute position within the container you will need to assign the AbsoluteLayout.LayoutFlags attached property. You will also want to assign the AbsoluteLayout.LayoutBounds attached property to give the elements their bounds.

The positional values are independent of the device pixels, and the LayoutFlags mentioned previously support such independence. Code Listing 8 provides an example based on proportional dimensions and absolute position for child controls.

Code Listing 8

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="App1.MainPage">

 

    <AbsoluteLayout Margin="10">

        <Label Text="First Label" 

               AbsoluteLayout.LayoutBounds="0, 0, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="Red"/>

        <Label Text="Second Label" 

               AbsoluteLayout.LayoutBounds="0.20, 0.20, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="DarkBlue"/>

        <Label Text="Third Label" 

               AbsoluteLayout.LayoutBounds="0.40, 0.40, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="DarkViolet"/>

        <Label Text="Fourth Label" 

               AbsoluteLayout.LayoutBounds="0.60, 0.60, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="DarkGreen"/>

    </AbsoluteLayout>

</ContentPage>

Figure 26 shows the result of the AbsoluteLayout example.

Absolute positioning with AbsoluteLayout

Figure 26: Absolute positioning with AbsoluteLayout

The ScrollView

The special layout ScrollView allows you to present content that cannot fit on one screen and should be scrolled. Its usage is very simple:

    <ScrollView x:Name="Scroll1">

        <StackLayout>

            <Label Text="My favorite color:" x:Name="Label1"/>

            <BoxView BackgroundColor="Green" HeightRequest="1000" />

        </StackLayout>

    </ScrollView>

You basically add a layout or visual elements inside the ScrollView, 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 Always, Never, and Default.

Additionally, you can specify the Orientation property (with values Horizontal or Vertical) to set the ScrollView to scroll only horizontally or only vertically. The reason the layout has a name in the sample usage is that you can interact with the ScrollView programmatically, invoking its ScrollToAsync method to move its position based on two different options.

Consider the following lines:

Scroll1.ScrollToAsync(0, 100, true);
Scroll1.ScrollToAsync(Label1, ScrollToPosition.Start, true);

In the first case, the content at 100 px from the top is visible. In the second case, the ScrollView moves the specified control at the top of the view and sets the current position at the control’s position. Possible values for the ScrollToPosition enumeration are:

·     Center: Scrolls the element to the center of the visible portion of the view.

·     End: Scrolls the element to the end of the visible portion of the view.

·     MakeVisible: Makes the element visible within the view.

·     Start: Scrolls the element to the start of the visible portion of the view.

Note that you should never nest ScrollView layouts, and you should never include views that implement scrolling, such as the CollectionView.

The Frame

The Frame is a very special view in .NET MAUI because it is implemented as a control but used as a layout. It provides an option to draw a colored border around the visual element it contains, and optionally add extra space between the Frame’s bounds and the visual element. Code Listing 9 provides an example.

Code Listing 9

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="App1.MainPage">

    <Frame BorderColor="Red" CornerRadius="3" 

           HasShadow="True" Margin="20">

        <Label Text="Label in a frame"

               HorizontalOptions="Center"

               VerticalOptions="Center"/>

    </Frame>

</ContentPage>

The BorderColor property is assigned with the color for the border, the CornerRadius property is assigned with a value that allows you to draw circular corners, and the HasShadow property allows you to display a shadow. Figure 27 provides an example.

Drawing a Frame

Figure 27: Drawing a Frame

The Frame will be resized proportionally based on the parent container’s size.

Tip: In Xamarin.Forms, the property that represents the border color is called OutlineColor.

The TwoPaneView

The TwoPaneView is a special layout that provides support for devices with two screens (such as the Microsoft Surface Duo), generally referred to as foldable devices. It represents a container with two views that size and position content in the available space, either side-by-side or top-to-bottom. It is exposed by the same-named class, which inherits from Grid. This layout is not part of the .NET base class library, so you need to first install the Microsoft.Maui.Controls.Foldable NuGet package. Once you have installed this NuGet package, you need to change the CreateMauiApp method in the MauiProgram.cs file with the lines referenced by the comments in the following code:

using Microsoft.Maui.Foldable; // Add this namespace reference

...

public static MauiApp CreateMauiApp()

{

    var builder = MauiApp.CreateBuilder();

    ...

    builder.UseFoldable(); // Add this invocation

    return builder.Build();

}

For Android, you then need to open the MainActivity.cs file located under Platforms\Android and replace the ConfigurationChanges assignment in the Activity attribute as follows:

ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize

    | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.UiMode

At this point, you can use the TwoPaneView in the user interface of a page. You first need to add an XML namespace reference that points to the appropriate assembly, and then you need to use the layout as the root element of the page. Code Listing 10 provides an example, where you can also see how the TwoPaneView exposes two panes, called Pane1 and Pane2.

Code Listing 10

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="MauiApp1.FoldablePage"

             xmlns:foldable="clr-namespace:Microsoft.Maui.Controls.Foldable;assembly=Microsoft.Maui.Controls.Foldable"

             Title="FoldablePage">

    <foldable:TwoPaneView x:Name="twoPaneView">

        <foldable:TwoPaneView.Pane1

        BackgroundColor="#dddddd">

            <Label

            Text="Pane 1 on the first screen"

            FontSize="32"

            HorizontalOptions="Center" />

        </foldable:TwoPaneView.Pane1>

        <foldable:TwoPaneView.Pane2>

            <VerticalStackLayout BackgroundColor="LightBlue">

                <Label Text="Pane2 on the second screen"

                       TextColor="Red"/>

            </VerticalStackLayout>

        </foldable:TwoPaneView.Pane2>

    </foldable:TwoPaneView>

</ContentPage>

Both the Pane1 and Pane2 objects derive from View, so they can contain any visual element.

Controlling the TwoPaneView

The TwoPaneView supports the following three modes, but only one can be the active mode:

·     SinglePane: Only one pane is currently visible.

·     Wide: Both panes are laid out horizontally, one on the left and one on the right. When on two screens, this is the mode for portrait orientation.

·     Tall: Both panes are laid out vertically, one on the top and one on the bottom. When on two screens, this is the mode for landscape orientation.

Certainly, the TwoPaneView can also work with one screen. If this is the case, it is possible to manage the following properties:

·     MinTallModeHeight: This represents the minimum height the control must be to enter Tall mode.

·     MinWideModeWidth: This represents the minimum width the control must be to enter Wide mode.

·     Pane1Length: Sets the width of Pane1 in Wide mode, the height of Pane1 in Tall mode, and has no effect in SinglePane mode.

·     Pane2Length: Sets the width of Pane2 in Wide mode, the height of Pane2 in Tall mode, and has no effect in SinglePane mode.

It is worth mentioning that the PanePriority property can be used to prefer Pane1 or Pane2 when in SinglePane mode. At the moment, there is no foldable device emulator for .NET MAUI and the hardware is not very common yet; for this reason, a sample screenshot (see Figure 28) is taken from the official documentation.

An example of TwoPaneView (Source

Figure 28: An example of TwoPaneView (Source: Microsoft)

Note: Emulators for foldable devices are available in the Microsoft Edge DevTools for web development, but they are not useful for nonweb development scenarios.

The ContentView

The special container ContentView allows for aggregating multiple views into a single view and is useful for creating reusable, custom controls. Because the ContentView represents a stand-alone visual element, Visual Studio makes it easier to create an instance of this container with a specific item template.

In Solution Explorer, you can right-click the project name and then select Add New Item. In the Add New Item dialog box, select the .NET MAUI node and then the ContentView item, as shown in Figure 29. Make sure you select the XAML version of the template; otherwise, you will need to supply the user interface in C# code.

Adding a ContentView

Figure 29: Adding a ContentView

When the new file is added to the project, the XAML editor shows basic content made of the ContentView root element and a Label. You can add multiple visual elements, as shown in Code Listing 11, and then you can use the ContentView as you would with an individual control or layout.

Code Listing 11

<?xml version="1.0" encoding="UTF-8"?>

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 

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

             x:Class="App1.View1">

  <ContentView.Content>

      <VerticalStackLayout>

          <Label Text="Enter your email address:" />

          <Entry x:Name="EmailEntry" />

      </VerticalStackLayout>

  </ContentView.Content>

</ContentView>

It is worth mentioning that visual elements inside a ContentView can raise and manage events and support data binding, which makes the ContentView very versatile and perfect for building reusable views.

Styling the user interface with CSS

Like its predecessor, .NET MAUI allows you to style the user interface with Cascading Style Sheets (CSS). If you have experience with creating content with HTML, you might find this feature very interesting.

Note: CSS styles must be compliant with .NET MAUI in order to be consumed in mobile apps, since it does not support all CSS elements. For this reason, the feature should be considered as a complement to XAML, not a replacement. Before you decide to do serious styling with CSS in your mobile apps, make sure you read the documentation for further information about what is available and supported.

There are three options to consume CSS styles in a MAUI project: two in XAML, and one in C# code.

Defining CSS styles as a XAML resource

Note: Examples in this section are based on the ContentPage object since you have not read about other pages yet, but the concepts apply to all pages deriving from Page. Chapter 6 will describe in detail all the available pages in .NET MAUI.

The first way you can use CSS styles in MAUI is by defining a StyleSheet object within the resources of a page, like in the following code snippet:

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

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

             x:Class="Layouts.CSSsample">

    <ContentPage.Resources>

        <ResourceDictionary>

            <StyleSheet>

                <![CDATA[

^contentpage {

background-color: lightgray; }

stacklayout {

margin: 20; }

]]>

            </StyleSheet>

        </ResourceDictionary>

</ContentPage.Resources>

</ContentPage>

In this scenario, the CSS content is enclosed within a CDATA section.

Note: Names of visual elements inside a CSS style must be lowercase.

For each visual element, you supply property values in the form of key/value pairs. The syntax requires the visual element name, and enclosed within brackets, the property name followed by a colon and the value followed by a semicolon, such as stacklayout { margin: 20; }. Notice how the root element, contentpage in this case, must be preceded by the ^ symbol. You do not need to do anything else because the style will be applied to all the visual elements specified in the CSS.

Consuming CSS files in XAML

The second option for consuming a CSS style in XAML is from an existing .css file. First, you need to add your .css file to the project and set its BuildAction property as EmbeddedResource. The next step is to add a StyleSheet object to a ContentPage’s resources and assign its Source property with the .css file name, as follows:

    <ContentPage.Resources>

        <ResourceDictionary>

            <StyleSheet Source="/mystyle.css"/>

        </ResourceDictionary>

    </ContentPage.Resources>

Obviously, you can organize your .css files into subfolders; for example, the value for the Source property could be /Assets/mystyle.css.

Consuming CSS styles in C# code

The last option you have for consuming CSS styles is using C# code. You can create a CSS style from a string (through a StringReader object), or you can load an existing style from a .css file, but in both cases the key point is that you still need to add the style to a page’s resources. The following code snippet demonstrates the first scenario, where a CSS style is created from a string and added to the page’s resources:

using (var reader =

       new StringReader

           ("^contentpage { background-color: lightgray; }

             stacklayout { margin: 20; }"))

{

       // "this" represents a page

       // StyleSheet requires a using Xamarin.Forms.StyleSheets directive

       this.Resources.Add(StyleSheet.FromReader(reader));

}

For the second scenario, loading the content of a CSS style from an existing file, an example is provided by the following code snippet:

var styleSheet = StyleSheet.FromAssemblyResource(IntrospectionExtensions.

                GetTypeInfo(typeof(Page1)).Assembly,

                "Project1.Assets.mystyle.css");

this.Resources.Add(styleSheet);

The second snippet is a bit more complex since the file is loaded via reflection (and in fact it requires a using System.Reflection directive to import the IntrospectionExtensions object). Notice how you provide the file name, including the project name (Project1) and the subfolder (if any) name that contains the .css file.

Chapter summary

Mobile apps require dynamic user interfaces that can automatically adapt to the screen size of different device form factors. In .NET MAUI, creating dynamic user interfaces is possible through a collection of so-called layouts.

The HorizontalStackLayout, VerticalStackLayout, and StackLayout allow you to arrange controls near one another both horizontally and vertically. The FlexLayout does the same, but it is also capable of wrapping visual elements.

The Grid allows you to arrange controls within rows and columns; the AbsoluteLayout allows you to give controls an absolute position; the RelativeLayout allows you to arrange controls based on the size and position of other controls or containers; the ScrollView layout allows you to scroll the content of visual elements that do not fit in a single page; the Frame layout allows you to draw a border around a visual element; and the ContentView allows you to create reusable views.

In the last part of the chapter, you saw how you can style visual elements using CSS stylesheets, in both XAML and imperative code, but these must be compliant to .NET MAUI requirements and should only be considered as a complement to XAML (and not a replacement).

Now that you have a basic knowledge of layouts, it’s time to discuss common controls that allow you to build the functionalities of the user interface, arranged within the layouts 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.