1

I am creating a basic MAUI app (Android only) using very basic Shell Navigation. Could anyone confirm (or not) whether the following is a valid way to do this? It works, but when navigating, occasionally the wrong page is briefly displayed before settling on the correct one.

I have no need of Flyout or Tab menus. All pages are added as Singletons in MauiProgram.cs. e.g.

builder.Services.AddSingleton<MainPage>();

All pages have routes registered in AppShell.xaml.cs. e.g.

Routing.RegisterRoute(nameof(MainPage), typeof(MainPage));

All pages have buttons to open other pages using [RelayCommand] in a ViewModel. e.g.

await Shell.Current.GoToAsync(nameof(Page1), false);

The routing structure is flat in AppShell.xaml:

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MyMauiApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyMauiApp.Views"
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="MainPage"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />
    <ShellContent
        Title="Page1"
        ContentTemplate="{DataTemplate local:Page1}"
        Route="Page1" />
    <ShellContent
        Title="Page2"
        ContentTemplate="{DataTemplate local:Page2}"
        Route="Page2" />

etc ...

MainPage goes to Page1,
Page1 to Page2 (or back to MainPage),
Page2 to Page3 (or back to Page1),
Page3 to Page4 (or back to Page1) etc.

It may not go through all pages forwards and backwards in sequence (I would like to be able to go to any page from any other). This works, but particularly when going back (using protected override bool OnBackButtonPressed() in the code behind), a different page is briefly displayed. e.g. in Page3Page.xaml.cs

protected override bool OnBackButtonPressed()
{
    page3PageViewModel.PageGoBack();
    return true;
}

and in page3PageViewModel.cs

public async void PageGoBack()
{
    await Shell.Current.GoToAsync("//" + nameof(Page1), false); 
}

The result is right but it looks messy. Suggestions welcome.

  • Add to question the code you have in your override of `OnBackButtonPressed`. – ToolmakerSteve Dec 07 '22 at 04:57
  • Done. It calls a method in the ViewModel. – John Dinning Dec 07 '22 at 05:43
  • I don't know why it displays a different page briefly, but if you know you are going back, then why not let `OnBackButtonPressed` do its default behavior (no override)? Or call the equivalent `await Shell.Current.GoToAsync("..");`. – ToolmakerSteve Dec 07 '22 at 19:23
  • 1
    Thanks for your interest ToolmakerSteve. Following your suggestions eventually led me to the solution. "why not let OnBackButtonPressed do its default behavior (no override)?" I have found that after navigating around a couple of pages, that the Hardware Back Btn stops doing anything. I have not figured out why yet. "Or call the equivalent await Shell.Current.GoToAsync("..");" This gave me a 'Ambiguous routes matched for: ...' error. This led me to realise that my routing was messed up. The solution below fixed this and the brief display of another page, but not back button issue. – John Dinning Dec 08 '22 at 02:49

1 Answers1

1

The answer was not to include the Route in the AppShell.xaml (visual hierarchy) and register the same route in the code behind. It was necessary only to include the MainPage in the Visual Hierarchy in AppShell.xaml, e.g.:

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MyMauiApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyMauiApp.Views"
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="MyMauiApp"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />
</Shell>

The other pages are like detail pages and their routes can be registered in AppShell.xaml.cs like this:

namespace MyMauiApp;

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

        Routing.RegisterRoute(nameof(Page1), typeof(Page1));
        Routing.RegisterRoute(nameof(Page2), typeof(Page2));
        Routing.RegisterRoute(nameof(Page3), typeof(Page3));
    }
}

As the documentation says (that I had missed):

'additional routes can be explicitly registered for any detail pages that aren't represented in the Shell visual hierarchy. This is accomplished with the Routing.RegisterRoute method'

'These detail pages can then be navigated to using URI-based navigation, from anywhere within the app. The routes for such pages are known as global routes.'

These pages can be navigated to directly with only the name. e.g. await Shell.Current.GoToAsync("Page1");