Endless loop trying to navigate through the app with Routing.RegisterRoute and await Shell.Current.GoToAsync

MrZabbah 21 Reputation points
2021-06-30T20:32:31.707+00:00

Hi everyone I have a big problem
I'm new using Xamarin and I'm learning while developing my first app. Now, I'm trying to achieve Shell Navegation with pages that are not in the Shell Content (for example, a detail page of an object).
In many tutorials they used the following code:

On the AppShell constructor we define the Routing:
-Routing.RegisterRoute(nameof(MyCoffeeDetailsPage), typeof(MyCoffeeDetailsPage));

MyCoffeeDetailsPage is the Page I want to move on. It's empty, just default settings

Next, on the modelview we create an AsyncCommand to control the navegation:

  • public AsyncCommand TravelCommand { get; }
  • public CoffeeEquipmentViewModel()
    {
    TravelCommand = new AsyncCommand(Travel);
    }
  • async Task Travel ()
    {
    var route = $"{nameof(MyCoffeeDetailsPage)}";
    await Shell.Current.GoToAsync(nameof(MyCoffeeDetailsPage));
    }

Now, everything is created, the next step is on the AXML binding this command to the proper button

  • <Button Text="Travel" Command="{Binding TravelCommand}"/>

It seems that this should works, but when I press the button the app crashes. Besides, I debug what is going on and the problem is the next one:

  • The await sentences on Travel calls the constructor of MyCoffeeDetailsPage. Inside this constructor, it executes the InitializeComponent and when it finish... it comes again to the constructor and the InitializeComponent in an endless loop.

Someone knows what is going on??

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,293 questions
0 comments No comments
{count} votes

Accepted answer
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 26,221 Reputation points Microsoft Vendor
    2021-07-06T09:40:45.887+00:00

    Hello,
    Welcome to our Microsoft Q&A platform!

    I tried your code, the issue is about MyCoffeeDetailsPage.xml, you can bind a ViewModel.

    <ContentPage.BindingContext>  
    <!--you can bind a ViewModel instead of view -->  
    <views:MyCoffeeDetailsPage/>  
    </ContentPage.BindingContext>  
    

    I create a new page and find the route you used is right.

    public AppShell()  
    {  
    InitializeComponent();  
    Routing.RegisterRoute(nameof(MyCoffeeDetailsPage), typeof(MyCoffeeDetailsPage));  
    Routing.RegisterRoute(nameof(CoffeeEquipmentPage), typeof(CoffeeEquipmentPage));  
    Routing.RegisterRoute(nameof(MyNewPage1), typeof(MyNewPage1));  
    }  
    
    async Task Travel ()  
    {  
    var route = $"{nameof(MyNewPage1)}";  
    await Shell.Current.GoToAsync(route);  
    }  
    

    Best Regards,
    Wenyan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 26,221 Reputation points Microsoft Vendor
    2021-07-01T09:33:23.283+00:00

    Hello,
    Welcome to our Microsoft Q&A platform!
    I am not sure where you added this button. It seams like the GoToAsync method has some issues. If you want to click the button on the first page(MyCoffeePage) to go to the next page(MyCoffeeDetailsPage), the following code shows a sample:

    shell page

    <TabBar>  
    <ShellContent Title="About" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />  
    <ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{DataTemplate local:ItemsPage}" />  
    <ShellContent Title="CoffeeDetails" Icon="icon_about.png" Route="MyCoffeePage" ContentTemplate="{DataTemplate local:MyCoffeePage}" />  
    </TabBar>  
    
    public AppShell()  
    {  
    InitializeComponent();  
    Routing.RegisterRoute(nameof(ItemDetailPage), typeof(ItemDetailPage));  
    Routing.RegisterRoute(nameof(NewItemPage), typeof(NewItemPage));  
    Routing.RegisterRoute(nameof(MyCoffeePage), typeof(MyCoffeePage));  
    Routing.RegisterRoute(nameof(MyCoffeeDetailsPage), typeof(MyCoffeeDetailsPage));  
    }  
    

    MyCoffeePage

    <Button Text="Travel" Command="{Binding TravelCommand}"/>  
    

    CoffeeEquipmentViewModel

    public class CoffeeEquipmentViewModel : BaseViewModel  
    {  
    public CoffeeEquipmentViewModel()  
    {  
    TravelCommand = new AsyncCommand(Travel);  
    }  
    public AsyncCommand TravelCommand { get; }  
    async Task Travel()  
    {  
    await Shell.Current.GoToAsync("/MyCoffeeDetailsPage");  
    }  
    }  
    

    For more information, you can refer:
    https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation

    Best Regards,
    Wenyan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  2. MrZabbah 21 Reputation points
    2021-07-01T15:09:51.017+00:00

    Hi! Thanks for your answer. I use the code above and it continues doing the same thing. I've created the button on the MyCoffeePage XAML in the ListView.Footer tab

        <ListView.Footer>
            <Button Text="Travel" Command="{Binding TravelCommand}"/>
        </ListView.Footer>
    

    I think the problem is here for some reason. Do I have to add MyCoffeeDetailsPage to the shell content?

    Here is the whole code of the xaml in MyCoffeePage
    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodels="clr-namespace:MyCoffeeApp.ViewModels"
    xmlns:model="clr-namespace:MyCoffeeApp.Models"
    xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
    x:Class="MyCoffeeApp.Views.CoffeeEquipmentPage"
    BackgroundColor="White"
    x:DataType="viewmodels:CoffeeEquipmentViewModel"
    x:Name="CoffeePage">
    <!--This is called compiled bindings and increase performance of data binding and give me compile time checks -->

    <ContentPage.BindingContext>
        <!--Give intellisense -->
        <viewmodels:CoffeeEquipmentViewModel/>
    </ContentPage.BindingContext>
    
    <ContentPage.Resources>
        <ResourceDictionary>
            <xct:ItemSelectedEventArgsConverter x:Key="ItemSelectedEventArgsConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>
    
    <ListView
        SelectedItem="{Binding SelectedCoffee, Mode=TwoWay}"
        CachingStrategy="RecycleElement"
        BackgroundColor="Transparent"           
        ItemsSource="{Binding Coffee}"      
        HasUnevenRows="True"
        SeparatorVisibility="None"
        IsPullToRefreshEnabled="True"
        IsRefreshing="{Binding IsBusy, Mode=OneWay}" 
        RefreshCommand="{Binding RefreshCommand}"
        RefreshControlColor="OrangeRed"
        SeparatorColor="Red">
        <!--Only view model update the ui, not reverse-->
        <!--It has scrolling capability, HasUnevenRows adjust height automatically RowHeight="100"
            RecicleElement is super important and gives performance
         GroupDisplayBinding="{Binding Key}" 
        IsGroupingEnabled="True"
                IsGroupingEnabled="True"
        GroupDisplayBinding="{Binding Key}"-->
    
        <ListView.Behaviors>
            <xct:EventToCommandBehavior
                EventName="ItemSelected"
                Command="{Binding SelectedCommand}"
                EventArgsConverter="{StaticResource ItemSelectedEventArgsConverter}"/>
        </ListView.Behaviors>
    
        <ListView.ItemTemplate>
            <!--Allows modify the template of the cell of an item-->
            <DataTemplate x:DataType="model:Coffee">
                <!--Every item template is a data template, there are text cells, switch cells, image cells, but we are goint to create custom viewCells-->
                <ViewCell>
                    <ViewCell.ContextActions>
                        <!--When pressing shows a menu-->
                        <MenuItem Text="Favourite" 
                                  Command="{Binding 
                            Source={x:Reference CoffeePage},
                            Path= BindingContext.FavouriteCommand}"
                                  CommandParameter="{Binding .}"/>
                        <MenuItem Text="Delete" IsDestructive="True"/>
                    </ViewCell.ContextActions>
                    <Grid Padding="10" RowDefinitions="Auto, Auto" ColumnDefinitions="Auto, Auto">
                        <Frame BackgroundColor="AliceBlue"
                               CornerRadius="20"
                               HasShadow="True">
                            <StackLayout Orientation="Horizontal">
                                <Image Source="{Binding Image}"
                                       WidthRequest="66"/>
                                <StackLayout VerticalOptions="Center">
                                    <Label
                                        VerticalOptions="Center"
                                        Text="{Binding Name}"
                                        FontSize="Large"
                                        TextColor="{StaticResource TextColor}"/>
                                    <Label
                                        VerticalOptions="Center"
                                        Text="{Binding Roaster}"
                                        FontSize="Large"
                                        TextColor="{StaticResource TextColor}"/>
                                </StackLayout>
                            </StackLayout>
                        </Frame>
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    
        <ListView.Header>
            <StackLayout>
                <StackLayout Orientation="Horizontal" BackgroundColor="{StaticResource Primary}">
                    <Image Source="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/495f34ea-e9dc-412f-a873-6c31cde052c6/dc06j59-0aaeea8c-aafc-4a25-9a2a-30c25bf712f5.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcLzQ5NWYzNGVhLWU5ZGMtNDEyZi1hODczLTZjMzFjZGUwNTJjNlwvZGMwNmo1OS0wYWFlZWE4Yy1hYWZjLTRhMjUtOWEyYS0zMGMyNWJmNzEyZjUucG5nIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.e3QLhHCvfol1wVSLVR1fzKFfd1UOIBCfMWc1zxh_UNA"
                                       WidthRequest="66"/>
                    <Label HorizontalOptions="Center" VerticalOptions="Center" Text="MOJACAR 2021" FontSize="48" TextColor="White"/>
                </StackLayout>
                <StackLayout Padding="5">
                    <Frame BackgroundColor="CadetBlue" CornerRadius="20" HasShadow="True" BorderColor="Black" Padding="15">
                        <Label Text="WIDGET DEL TIEMPO SEMANAL" FontSize="36" />
                    </Frame>
                </StackLayout>
            </StackLayout>
        </ListView.Header>
    
        <ListView.Footer>
            <Button Text="Travel" Command="{Binding TravelCommand}"/>
        </ListView.Footer>
    
    </ListView>
    

    </ContentPage>