Categories
.NET .NET 8 .NET 9 .NET MAUI Android Blazor C# Code Desktop Developer Getting Started Hybrid iOS macOS Mobile MVVM Windows Xamarin Xamarin.Forms XAML

XAML Basics: Building UI with .NET MAUI and More – Part 2

This article represents the second installment of the XAML for Beginners series, which elucidates the concept of declarative markup in the context of defining UI in .NET applications. All articles within this series are accessible from here.

The initial article focused mainly on introducing XAML and its building blocks.

In this article, the focus will be on the following:

  • Attached Properties
  • Generics
  • Passing Arguments

Attached Properties:

  • An attached property in XAML is a specialized bindable property that allows child elements to store a value in a parent element.
  • This is used primarily for layout, positioning, or customization, enabling child elements to communicate layout information to their parent container.
  • These are defined in the parent class but are set on child elements. The syntax specifies the parent class and the property name using the Class.Property notation.

For example, the Row and Column properties of the Grid layout are attached properties meant for the child controls within the Grid.

Likewise, the Shell encompasses a variety of attached properties that enable the customization of the page presented within the Shell.

The example below illustrates a two-column Grid layout, with the Entry in the first column and the Button in the second.

<Grid ColumnDefinitions="*,*">
  <Entry Grid.Column="0" />
  <Button Grid.Column="1" />
</Grid>

The Settings page is presented as a Modal page.

<ContentPage
  x:Class="MyApp.Views.SettingsPage"
  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  Title="Settings"
  Shell.PresentationMode="ModalAnimated">
</ContentPage>

Generics:

Generics serve a crucial function in enhancing both the performance and type safety of a program.

.NET MAUI XAML does indeed facilitate the use of generics to a certain extent by incorporating the x:TypeArguments attribute.

This attribute may also be applied to the root element of the XAML document, thereby marking that the base class of the UI element is a generic type.

<vw:MauiPage
  x:Class="MyApp.Views.HomePage"
  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:vm="clr-namespace:MyApp.ViewModels"
  xmlns:vw="clr-namespace:MyApp.Views"
  x:TypeArguments="vm:HomeViewModel">
</vw:MauiPage>

The definition of the code-behind is as follows:

using MyApp.ViewModels;

namespace MyApp.Views;

// Inherited from a generic base class
public partial class HomePage : MauiPage<HomeViewModel> {}

// Assuming they're defined somewhere

public class MauiPage : ContentPage {}

public class MauiPage<TViewModel> : MauiPage 
    where TViewModel : class, INotifyPropertyChanged {}

Defining generic classes in .NET MAUI XAML, with the x:TypeArguments directive, is unsupported.

Generics can also be applied in various other scenarios. The following example delineates a list of strings as the item source for the bindable layout.

It’s important to note that all the properties of BindableLayout are Attached Properties. Thus, regardless of whether it is referred to as Attributes or Elements, it must consistently be prefixed with the corresponding type name.

<ContentPage
  x:Class="MyApp.Views.HomePage"
  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib">
  <StackLayout
    HorizontalOptions="Center"
    VerticalOptions="Center">
    <BindableLayout.ItemsSource>
      <!-- Defines a list of string -->
      <scg:List x:TypeArguments="x:String">
        <x:String>Red</x:String>
        <x:String>Orange</x:String>
        <x:String>Yellow</x:String>
        <x:String>Green</x:String>
        <x:String>Blue</x:String>
        <x:String>Indigo</x:String>
        <x:String>Violet</x:String>
      </scg:List>
    </BindableLayout.ItemsSource>
    <BindableLayout.ItemTemplate>
      <DataTemplate x:DataType="x:String">
        <Label
          HorizontalOptions="Center"
          Text="{Binding}"
          VerticalOptions="Center" />
      </DataTemplate>
    </BindableLayout.ItemTemplate>
  </StackLayout>
</ContentPage>

Multiple Type Arguments and Nested Types:

While defining multiple-type arguments, such as a KeyValuePair<K, V>, and complex nested types (such as a list of lists), it is imperative to acknowledge that the outer angle bracket will be supplied by the XAML parser; furthermore, any inner angle brackets, if present, should be substituted with parentheses.

Below is an example of a nested list of strings:

<!-- var nestedList = new List<List<string>>(); -->
<StackLayout>
  <BindableLayout.ItemsSource>
    <!-- Outer list -->
    <scg:List x:TypeArguments="scg:List(x:String)">
      <!-- Inner list -->
      <scg:List x:TypeArguments="x:String">
        <x:String>Apple</x:String>
        <x:String>Mango</x:String>
        <x:String>Orange</x:String>
      </scg:List>
    </scg:List>
  </BindableLayout.ItemsSource>
</StackLayout>

Pass Arguments:

In the preceding article, it has been stated that XAML elements require a public, parameterless constructor for the UI element to operate efficiently. However, it is important to note that this requirement may be bypassed under specific circumstances.

This is accomplished through the utilization of the x:Arguments attribute.

There are two scenarios where this can be applied.

  • When a XAML element is utilized
  • When invoking a Factory Method to obtain an instance of the specified object type

In the example presented below, an instance of NavigationPage is assigned to the MainPage of the Application or the Page property of the Window, as appropriate. Therefore, it is feasible to pass the HomePage as an argument.

On .NET MAUI 8:

XAML:

<Application
  x:Class="MyApp.App"
  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:vw="clr-namespace:MyApp.Views">
  <Application.MainPage>
    <NavigationPage>
      <x:Arguments>
        <vw:HomePage />
      </x:Arguments>
    </NavigationPage>
  </Application.MainPage>
</Application>

C#:

using MyApp.Views;

namespace MyApp;

public partial class App : Application
{
  public App()
  {
    InitializeComponent();
    // Represented in XAML
    //MainPage = new NavigationPage(new HomePage());
  }
}

On .NET MAUI 9:

The MainPage property is now obsolete. To learn more about this transition from the Application’s MainPage to the Window’s Page, refer to this article.

XAML:

Since Page is the content property of the Window, the Window.Page wrapper node is optional.

<Window
  x:Class="MyApp.MainWindow"
  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:vw="clr-namespace:MyApp.Views">
  <!-- The below wrapper node is optional. -->
  <Window.Page>
    <NavigationPage>
      <x:Arguments>
        <vw:HomePage />
      </x:Arguments>
    </NavigationPage>
  </Window.Page>
</Window>

C#:

using MyApp.Views;

namespace MyApp;

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
    // Represented in XAML
    //Page = new NavigationPage(new HomePage());
  }
}

Factory Method:

A factory method is a public static method that returns objects or values of the same type as the class or structure that defines the methods.

<!-- Defining #512BD4 as a style -->
<Color
  x:Key="DotnetPurple"
  x:FactoryMethod="FromRgb">
  <x:Arguments>
    <x:Byte>81</x:Byte>
    <x:Byte>43</x:Byte>
    <x:Byte>212</x:Byte>
  </x:Arguments>
</Color>

In the course of our exploration of XAML, we have achieved significant progress. The forthcoming article will examine the Extensions that further simplify the XAML definition.

Happy coding. Stay connected as we continue to learn and share the experiences from this exciting journey of being a .NET developer.

2 replies on “XAML Basics: Building UI with .NET MAUI and More – Part 2”

Comments are closed.

Discover more from Developer Thoughts

Subscribe now to keep reading and get access to the full archive.

Continue reading