简体   繁体   中英

Xamarin.Forms - Master/detail page and navigation history issue

I have an app which uses masterdetail page to show menu in all page. The navigation is happened in two way in my app. one from the menu and second way from Dashboard. so if i navigate to another page, and then press "BACK" button, it closes the application. It does not remember the navigation history. The master detail page is as below:

 public class RootPage : MasterDetailPage
    {
        public RootPage ()
        {
            var menuPage = new MenuPage ();

            menuPage.Menu.ItemSelected += (sender, e) => NavigateTo (e.SelectedItem as MenuItem);

            Master = menuPage;
            Detail = new NavigationPage (new ContractsPage ());
        }

        void NavigateTo (MenuItem menu)
        {
            Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
            Detail =    new NavigationPage (displayPage);
            IsPresented = false;
        }
    }

so any ideas how to overcome this problem?

Like what @Sten-Petrov said: you are replacing the detail page and not triggering the history mechanism. To trigger the history mechanism you will need to do a PushAsync(Page) on the Navigation property of the Detail page.

In your example, change NavigateTo:

 void NavigateTo (MenuItem menu)
 {
     Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
     Detail.Navigation.PushAsync(displayPage);
 }

This will not replace the content but will bring up a new page with the back button functionality you want.

If you want back button functionality with the Master-Detail page then you'll need to customize the back stack process which, in my opinion, is not worth it. Just move to a different page/navigation structure in that case.

The issue here is you're not using the Navigation stack to perform transitions of your pages but instead replace an item on your own page, so there's no navigation history to go "back" other than the page that navigated to your MasterDetailPage.

You can resolve the problem by creating a new MenuMasterDetail.cs class that inherits MasterDetailPage and initializes a menu, then create MenuItem_A_Page.xaml (or .cs) that inherit from your common base and in your common base class you'll use Navigation.PushAsync(...) to transition between pages.

base class:

public class MenuDetailPage: MasterDetailPage{
  public MenuDetailPage(): base(){
    this.Master = BuildMyMenuListHere(); // the menu items will also define navigation targets
  }
}

subclass in CS:

public class FirstDetailWithMenuPage: MenuDetailPage{
  public FirstDetailWithMenuPage()
    : base() // this creates the menu
  {
    this.Detail = new StackLayout{  // change this however you need
      Children = {
        new Label { Text = "This is the first page" },
        new Button { Text= "Ok"},
     }
  }
}

Subclass in XAML (along with the CS from above, minus the part where the Detail is set):

<local:FirstDetailWithMenuPage namespace:YourNamespace;assembly=YourAssemblyName" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-n xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="FirstDetailWithMenuPage">
    <local:FirstDetailWithMenuPage.Detail>
...

Also update your App.cs to return a navigation page with the first master/detail page you have (not the base one):

App.cs:

public static Page GetMainPage ()
{
  return new NavigationPage(new FirstDetailWithMenuPage());
}

I was having same issue, Detail.Navigation.PushAsync(itemSelected) makes hamburger menu vanish and also creating another sub-class to retain seemed big work on code and performance. So, I decided to use my own stack datatype for Master detail page. It was bit tricky to keep track and code but working fine.

Initialize it at the app load with current Detail page and for each item selected Push new page on top of stack.

public partial class MyMasterDetailPage: MasterDetailPage
    {
        private Stack navigationStack = new Stack();
        public MyMasterDetailPage()
        {
            InitializeComponent();
            navigationStack.Push(Detail);
            try
            {
                masterPage.listView.ItemSelected += OnItemSelected;

            }
            catch (Exception exc)
            {

                System.Diagnostics.Debug.WriteLine(exc.Message);
            }

        }

Override OnBackButtonPressed() in same Page code behind

        protected override bool OnBackButtonPressed()
        {
            try
            {
                var lastPage = navigationStack.Pop();
                if (lastPage.Equals(Detail))
                    lastPage = navigationStack.Pop();

                Detail = (Page)lastPage;
                IsPresented = false;

               // to avoid app close when complete pop and new page is push on top of it 
                if (navigationStack.Count == 0) 
                    navigationStack.Push(Detail);
                return true;
            }
            catch (Exception)
            {

                return base.OnBackButtonPressed();
            }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM