Reset xamarin.forms.shell to initial page on back button

6.8k Views Asked by At

Very short version is I want to, in code, make the shell go to where it was, and how it looked, when it first displayed on app start.

I have a xamarin.forms.shell page which shows a number of content pages using flyout and tabs. When the shell initially loads, it shows the first flyout item content page, which is my "main activity/page" with the most common UI.

If I go to another flyout item content page, I would like the backbutton to navigate to the "main flyout" and only if back button is clicked on this "main flyout", should it leave the app.

While I can intercept the backbutton and navigate to other pages, it does not have the effect of clicking the "main page" flyout. If I do

Shell.Current.GoToAsync(name of route to my main flyout);

I do get to that main page, but as fullscreen and the flyout menu, toolbar and tabs are gone.

2

There are 2 best solutions below

1
On BEST ANSWER

For this you need to override the Back button behavior, in your desired content page by defining a command that will be fired when the user pressed the back button in that page and then navigate to your root page by it defined root:

CatsPage.Xaml

<Shell.BackButtonBehavior>
   <BackButtonBehavior Command="{Binding BackCommand}"/>
</Shell.BackButtonBehavior>

Code-Behind or ViewModel

public ICommand BackCommand { get; private set; }

public CatsPage()  //or VM constructor
{
    ...
BackCommand = new Command(async (x) => await Shell.Current.GoToAsync("///MainRoute"));
}

If you are using this content page as a Tab content in more than one FlyoutItem, but you only want this behavior to work on the the ContentPage residing in the first FlyoutItem you may add a conditional test based on page absolute route or Title property:

Xaml example from jiang answer:

<FlyoutItem Route="MainRoute"
            Title="Animals"
            FlyoutDisplayOptions="AsMultipleItems">
    <Tab Title="MainPage"
         Route="MainPage"
         Icon="paw.png">
        <ShellContent Route="cats"
                      Style="{StaticResource DomesticShell}"
                      Title="Cats"
                      Icon="cat.png"
                      ContentTemplate="{DataTemplate views:CatsPage}" />
        <ShellContent Route="dogs"
                      Style="{StaticResource DomesticShell}"
                      Title="Dogs"
                      Icon="dog.png"
                      ContentTemplate="{DataTemplate views:DogsPage}" />
    </Tab>

    <ShellContent Route="PageTwo"
                  Style="{StaticResource MonkeysShell}"
                  Title="Monkeys"
                  Icon="monkey.png"
                  ContentTemplate="{DataTemplate views:MonkeysPage}" />

    <ShellContent Route="cats"
                  Style="{StaticResource DomesticShell}"
                  Title="Cats2"
                  Icon="cat.png"
                  ContentTemplate="{DataTemplate views:CatsPage}" />
</FlyoutItem>

Code-Behind or ViewModel

public CatsPage() //or VM constructor
{
    ...
    BackCommand = new Command(async (x) => {
    if (Shell.Current.CurrentState.Location.ToString().Equals("//MainRoute/MainPage/Cats"))
      //popup to quit
else if (Shell.Current.CurrentState.Location.ToString().Equals("//MainRoute/Cats"))
        await Shell.Current.GoToAsync("///MainRoute");
    // or use to go back to previous: await Shell.Current.GoToAsync("..");
   });
}

Once again you need to properly define and use your Tabs and FlyoutItem routes hierarchy otherwise it will result in an exception.

2
On

If I go to another flyout item content page, I would like the backbutton to navigate to the "main flyout" and only if back button is clicked on this "main flyout", should it leave the app.

You could store a page flag type when each page shows to determine whether it's the main page. And the page flag type only need to define two type: One is 0(means main page), another is 1(other pages). Then when pressing physical back button, you can determine whether need to show the exit message to exit the app.

For example, using Xamarin.Essentials: Preferences to store flag in OnAppearing method of each page:

MainPage:

public partial class MainPage: ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        Preferences.Set("PageType", "0");
    }
}

OtherPage:

public partial class OtherPage : ContentPage
{
    public OtherPage()
    {
        InitializeComponent();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        Preferences.Set("PageType", "1");
    }
}

Then when back button be clicked, we can determine what we need to do.

private async void Button_Clicked(object sender, EventArgs e)
{
    var pageType = Preferences.Get("PageType", "0");
    if (pageType == "0")
    {
        // Exit application method
        ExitApplication();
    }
    else
    {
        // back to the Main Page
        await Shell.Current.GoToAsync($"//MainRoute/MainPage");
    }
}

Here is the Xaml code of FlyoutItem :

<FlyoutItem Route="MainRoute"
            Title="Animals"
            FlyoutDisplayOptions="AsMultipleItems">
    <Tab Title="MainPage"
         Route="MainPage"
         Icon="paw.png">
        <ShellContent Route="cats"
                      Style="{StaticResource DomesticShell}"
                      Title="Cats"
                      Icon="cat.png"
                      ContentTemplate="{DataTemplate views:CatsPage}" />
        <ShellContent Route="dogs"
                      Style="{StaticResource DomesticShell}"
                      Title="Dogs"
                      Icon="dog.png"
                      ContentTemplate="{DataTemplate views:DogsPage}" />
    </Tab>

    <ShellContent Route="PageTwo"
                  Style="{StaticResource MonkeysShell}"
                  Title="Monkeys"
                  Icon="monkey.png"
                  ContentTemplate="{DataTemplate views:MonkeysPage}" />
    <ShellContent Route="PageThree"
                  Style="{StaticResource ElephantsShell}"
                  Title="Elephants"
                  Icon="elephant.png"
                  ContentTemplate="{DataTemplate views:ElephantsPage}" />
    <ShellContent Route="PageFour"
                  Style="{StaticResource BearsShell}"
                  Title="Bears"
                  Icon="bear.png"
                  ContentTemplate="{DataTemplate views:BearsPage}" />
</FlyoutItem>