.Net MAUI /First Look #2

Introduction by Microsoft

This cannot be done better than by the original creators at Microsoft:

Lessons learned

Navigation from page to page in C# Net Maui is a bigger issue woth disuccing, Although it can be done with little code. On this page I'll only cover navigation, since it takes up a lot of space for examples.

Application Navigation

Maui uses routes to navigate between pages. That's the reason we'll define routes to every page and add navigation between them.

New associated Objects

First create a page and a viewmodel. Let's call the page DetailPage and the viewmodel DetailViewModel.cs. Behold the pattern here: Always use (Detail|[Page|ViewModel]) as a convention to know they are related. We'll again use the CommunityToolkit to simplify some property generation. Make the DetailViewModel partial and extend from ObservableObject. Finally pass the ViewModel via the constructor like so:

using MauiTest.ViewModel;

namespace MauiTest;

public partial class DetailPage : ContentPage
{
    public DetailPage(DetailViewModel vm)
    {
        InitializeComponent();
        BindingContext = vm;
    }
}

The new classes must be registered in out CreateMauiApp() Method. Keep in mind that this time we make the page transient (AddTransient) so it gets created every time we navigate here. The following code describes just that:

builder.Services.AddTransient<DetailPage>();
builder.Services.AddTransient<DetailViewModel>();

Routing Mechanism

Behold the standard App route points to the MainPage class. So this is the route that opens by default. Other routing options are not registered, yet.

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MauiTest.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiTest"
    Shell.FlyoutBehavior="Disabled">
    <ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />
</Shell>

Use the AppShell to add a new route. This way our application knows with which class a route is associated. Use any key you like but it easier to use the classname or a set of certain keys. We'll use the class name here to identify the route.

namespace MauiTest;

public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();

        // The name can be anything but it makes sense to use the object name
        Routing.RegisterRoute(nameof(DetailPage), typeof(DetailPage));
    }
}

UI Interaction and Navigation

There are plenty of gesture recognizers. We wanna use a TapGestureRecognizer which can simply be connected to a command. Just extend the XAML syntax that displays the bound Text property. Connect it to the Command on the BindingContext (which should be the ViewModel).

<Grid
    Padding="0,5">
    <Frame
        Background="White"
        CornerRadius="5">
        <Frame.GestureRecognizers>
            <TapGestureRecognizer
                Command="{Binding Source={RelativeSource AncestorType={x:Type vm:MainViewModel}}, Path=TapCommand}"
                CommandParameter="{Binding .}" />
            </Frame.GestureRecognizers>
            <Label
                TextColor="Black"
                Text="{Binding .}"
                FontSize="24" />
    </Frame>
</Grid>

The Command implementation will look like this, since we have used the classname as route identifier. The [RelayCommand] will also generate a bindable command for us.

[RelayCommand]
async Task Tap(string s)
{
    // Navigate to the other page via its name
    await Shell.Current.GoToAsync(nameof(DetailPage));
}

We can now navigate to the new page. Navigating back works similar to navigating through a filesaystem. For example ".." navigates back one page. Combine these with other pages that you want to navigate to. If for example you would wanna go back and then to a page that's called Export you could navigate to: "../Export". So to just go back we navigate to:

[RelayCommand]
async Task GoBack()
{
    await Shell.Current.GoToAsync("..");
}

Sending parameters

Just navigating somewhere sometimes doesn't cut it. We might also need to pass along some parameters. Behold the following example, where a parameter Text is passed along., where s is a string variable.

await Shell.Current.GoToAsync($"{nameof(DetailPage)}?TextVal={s}");

To pass along complex datatypes we'll use an extra dictionary like so:

await Shell.Current.GoToAsync($"{nameof(DetailPage)}?TextVal={s}",
new Dictionary<string, object>
{
    {"key1", obj1},
    {"key2", obj2},
    ...
});

The model must receive declarations associating parameters and member variables. Heading over to the ViewModel we can now mark it with QueryProperty. This way we'll know which parameters are supposed to be sent to which class properties.

[QueryProperty("Text", "TextVal")]
public partial class DetailViewModel : ObservableObject
{
    public string Text { get; set; }
}

Links & Resources

  • YouTube Video Introduction Series of Videos by Microsoft to introduce .Net MAUI
  • Sample Code The code for the sample app we're programming here
  • Aloha Kit There is an experimental project in .NET called Microsoft.Maui.Graphics.Controls (GraphicsControls) with drawn controls. The main goal of GraphicsControls is to validate if there are interest in .NET MAUI drawn controls, creating the controls that were available in Xamarin.Forms Visual with Cupertino, Fluent and Material Design.
  • Awesome .Net Maui .NET Multi-platform App UI (.NET MAUI) is a cross-platform framework for creating native mobile and desktop apps with C# and XAML. Using .NET MAUI, you can develop apps that can run on Android, iOS, macOS, and Windows from a single shared code-base.

First Page