0

I have a small .NET MAUI Application with about 18 pages. I was creating all of my routing on the code behind of the AppShell. Like this:

public AppShell()
{
    InitializeComponent();

    Routing.RegisterRoute(nameof(LogInPage), typeof(LogInPage));
    Routing.RegisterRoute(nameof(SignUpPage), typeof(SignUpPage));
    Routing.RegisterRoute(nameof(PasswordRecoveryPage), typeof(PasswordRecoveryPage));
    Routing.RegisterRoute(nameof(ModalitiesPage), typeof(ModalitiesPage));
    Routing.RegisterRoute(nameof(UserPage), typeof(UserPage));
    Routing.RegisterRoute(nameof(HomePage), typeof(HomePage));
    Routing.RegisterRoute(nameof(ConversationsPage), typeof(ConversationsPage));
    Routing.RegisterRoute(nameof(BookingsPage), typeof(BookingsPage));
    Routing.RegisterRoute(nameof(ProfessionalPage), typeof(ProfessionalPage));
    Routing.RegisterRoute(nameof(AddPaymentInfoPage), typeof(AddPaymentInfoPage));
    Routing.RegisterRoute(nameof(AddAddressPage), typeof(AddAddressPage));
    Routing.RegisterRoute(nameof(AddReviewPage), typeof(AddReviewPage));
    Routing.RegisterRoute(nameof(PlaygroundPage), typeof(PlaygroundPage));
    Routing.RegisterRoute(nameof(FavoritesPage), typeof(FavoritesPage));
    Routing.RegisterRoute(nameof(PostLoginPage), typeof(PostLoginPage));
}

However due to having to also register Tabs and a TabBar in the AppShell.xaml, and following some examples I've seen online I've opted for registering the routes in the XAML. I removed the registration in the code-behind and added via XAML. This is my AppShell.xaml as it stands:

<Shell
x:Class="Xen.Presentation.Mobile.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Xen.Presentation.Mobile"
xmlns:views="clr-namespace:Xen.Presentation.Mobile.Views"
Shell.FlyoutBehavior="Disabled">

<ShellContent
    Title="Onboarding"
    ContentTemplate="{DataTemplate views:OnboardingPage}"
    Route="OnboardingPage" />

<ShellContent
    Title="LogIn"
    ContentTemplate="{DataTemplate views:LogInPage}"
    Route="LogInPage" />

<TabBar Route="Main">
    <Tab
        Title="Inicio"
        Icon="home.png"
        Route="HomePage">
        <ShellContent Title="Home" ContentTemplate="{DataTemplate views:HomePage}" />
    </Tab>
    <Tab
        Title="Favoritos"
        Icon="bookings.png"
        Route="FavoritesPage">
        <ShellContent Title="Favorites" ContentTemplate="{DataTemplate views:FavoritesPage}" />
    </Tab>
    <Tab
        Title="Conversas"
        Icon="chat.png"
        Route="ConversationsPage">
        <ShellContent Title="Conversas" ContentTemplate="{DataTemplate views:ConversationsPage}" />
    </Tab>
    <Tab
        Title="Modalidades"
        Icon="modalities.png"
        Route="ModalitiesPage">
        <ShellContent Title="Modalidades" ContentTemplate="{DataTemplate views:ModalitiesPage}" />
    </Tab>
    <Tab
        Title="Perfil"
        Icon="user.png"
        Route="ProfileTab">
        <ShellContent
            Title="Perfil"
            ContentTemplate="{DataTemplate views:UserPage}"
            Route="UserPage" />
    </Tab>
</TabBar>

<ShellContent
    Title="SignUpPage"
    ContentTemplate="{DataTemplate views:SignUpPage}"
    Route="SignUpPage" />

<ShellContent
    Title="BookingsPage"
    ContentTemplate="{DataTemplate views:BookingsPage}"
    Route="BookingsPage" />

<ShellContent
    Title="PlaygroundPage"
    ContentTemplate="{DataTemplate views:PlaygroundPage}"
    Route="PlaygroundPage" />

<ShellContent
    Title="FavoritesPage"
    ContentTemplate="{DataTemplate views:FavoritesPage}"
    Route="FavoritesPage" />

<ShellContent
    Title="Professional"
    ContentTemplate="{DataTemplate views:ProfessionalPage}"
    Route="ProfessionalPage" />

<ShellContent
    Title="AddPaymenInfo"
    ContentTemplate="{DataTemplate views:AddPaymentInfoPage}"
    Route="AddPaymentInfoPage" />

<ShellContent
    Title="AddAddress"
    ContentTemplate="{DataTemplate views:AddAddressPage}"
    Route="AddAddressPage" />

<ShellContent
    Title="AddReview"
    ContentTemplate="{DataTemplate views:AddReviewPage}"
    Route="AddReviewPage" />

<ShellContent
    Title="PostReview"
    ContentTemplate="{DataTemplate views:PostReviewPage}"
    Route="PostReviewPage" />

<ShellContent
    Title="PostLogin"
    ContentTemplate="{DataTemplate views:PostLoginPage}"
    Route="PostLoginPage" />

</Shell>

I don't have any issues when using the TabBar for navigation after login. However some code that used to work now doesn't. For instance, in my UserPageViewModel I have some commands that navigate to other pages. This is the some of the code that now doesn't work anymore:

    private async Task OnAddAddress()
    {
        await Shell.Current.GoToAsync(nameof(AddAddressPage));
    }

    private async Task OnAddPaymentInfo()
    {
        await Shell.Current.GoToAsync(nameof(AddPaymentInfoPage));
    }

Now when I run any of these methods I get this exception:

System.Exception Message=Relative routing to shell elements is currently not supported. Try prefixing your uri with ///: ///AddAddressPage

If I do like it tells and run this code:

 await Shell.Current.GoToAsync("///AddAddressPage");

Or even:

 await Shell.Current.GoToAsync("//AddAddressPage");

Then I go to the AddAddressPage, but it seems like it clears the whole navigation stack and when I go back, I go back to the OS and the app goes to the background. Which makes it not a viable option to me.

After changing the routing to XAML I also get error when a page has parameters.For example, from my HomePage when I click on a professional on the list I was navigating to the ProfessionalPage, however after changing the routes to the XAML now when I run this code:

    private static async void OnProfessionalTapped(ProfessionalPreview item)
    {
        var parameters = new Dictionary<string, object>
        {
            { "ProfessionalId", item.Id }
        };
        
        // Using // to open the page even though I need to go back, just to test
        await Shell.Current.GoToAsync($"//{nameof(ProfessionalPage)}", parameters);
    }

I get this error:

Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Xen.Presentation.Mobile.Models.Professional' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path 'content', line 1, position 12.'

With this call stack:

enter image description here

Is there something wrong with my AppShell.xaml? Should I register the pages on the code-behind? Why?

I read the docs on the Shell navigation, including the part on relative routes, but I still can't figure it out. Also watched some videos:

And looked at some samples, but when it comes to shell it seems like most samples are focused on using Flyouts.

adamasan
  • 1,092
  • 1
  • 12
  • 33

2 Answers2

1

As a reference to .NET MAUI Shell navigation - .NET MAUI, the routes in an app should be unique and distinct. So you have set the route both in ShellContent via XAML and in the code-behind in like below:

  1. Set the route in ShellContent :
<ShellContent
    Title="AddAddress"
    ContentTemplate="{DataTemplate views:AddAddressPage}"
    Route="AddAddressPage" />
  1. Register the route in AppShell.xaml.cs:
Routing.RegisterRoute(nameof(AddAddressPage), typeof(AddAddressPage));
  1. Then you can navigate to AddAddressPage via Shell.Current.GoToAsync:
await Shell.Current.GoToAsync(nameof(AddAddressPage));
Alexandar May - MSFT
  • 6,536
  • 1
  • 8
  • 15
  • Hello, this isn't very clear to me. Should I add the routes both in the XAML and code-behind? Because currently I'm using only via XAML. One of the reasons I removed the code-behind registrations apart from what I mentioned in the post was this answer: https://stackoverflow.com/a/76011634/2534489. – adamasan Apr 21 '23 at 03:46
  • Yes, you need add the routes both in the XAML and code-behind. – Alexandar May - MSFT Apr 21 '23 at 05:33
0

I have the exact same problem. I raised it with Microsoft:

https://github.com/dotnet/maui/issues/13695

Don't expect a resolution any time soon though. They have over 2000 bugs and 6 developers working on them.

BuckBuchanan
  • 198
  • 13