Master-Detail Form back button with PushAsync

fsulserfsulser Member ✭✭
edited February 27 in Xamarin.Forms

I created initially a Master-Detail Forms App and I'm using the burger menu that was provided with this setup.
On my main page I set a listener on a label which opens a new Page with a back button instead of the burger menu with:

        async void OnXXXTappedAsync(object sender, EventArgs args)
        {
            await Navigation.PushAsync(new XXXPage());
        }

When I use the burger menu I want the same behaviour (instead of the burger menu on the second page I want a back button),
Therefore I removed the adding part to the MenuPages and added the PushAsync from above.

    public async Task NavigateFromMenu(int id)
        {
            if (!MenuPages.ContainsKey(id))
            {
                switch (id)
                {
                    case (int)MenuItemType.Startseite:
                        var navigationPage = new NavigationPage(new HomePage());
                        MenuPages.Add(id, navigationPage);
                        break;
                }
            }

            var newPage = MenuPages[id];

            if (newPage != null && Detail != newPage)
            {
                Detail = newPage;

                if (Device.RuntimePlatform == Device.Android)
                    await Task.Delay(100);

                IsPresented = false;
            }
            else
            {
                await Navigation.PushAsync(new SpielplanPage());

            }
        }

which throws an error:
`PushAsync is not supported globally on Android, please use a NavigationPage?

I also tried it in the MenuPage:

             ListViewMenu.ItemSelected += async (sender, e) =>
            {
                int id = (int) menuItems[0].Id;

                if (e.SelectedItem != null)
                {
                    id = (int)((HomeMenuItem)e.SelectedItem).Id;
                }

                if(id == 0)
                {
                    await RootPage.NavigateFromMenu(id);
                }
                else
                {
                    await Navigation.PushAsync(new SpielplanPage());
                }

            };

but then get the same error.

Best Answers

  • fsulserfsulser ✭✭
    edited February 28 Accepted Answer

    I tried now again the second approach and found a way, don't know why I wasn't able in the first try. Basically all what needs to be changed is something like shown in the snipped below in Mainpage in function NavigateFromMenu:

        public async Task NavigateFromMenu(int id)
        {
            switch (id)
            {
                   case (int)MenuItemType.Browse:
                        break;
                    case (int)MenuItemType.About:
                        PushPage(new AboutPage());
                        return;
            }
    
            var newPage = new NavigationPage(new HomePage());
            Detail = newPage;
    
            if (Device.RuntimePlatform == Device.Android)
                await Task.Delay(100);
    
            IsPresented = false;
        }
    
        public async void PushPage(ContentPage page)
        {
            await Detail.Navigation.PushAsync(page);
    
            if (Device.RuntimePlatform == Device.Android)
                await Task.Delay(100);
    
            IsPresented = false;
        }
    

    Just one remark, if the user clicks now on the Browse Item the main page will reload which is expected in my case.

    Thanks for the support

Answers

  • NMackayNMackay GBInsider, University mod
    edited February 27

    "`PushAsync is not supported globally on Android, please use a NavigationPage?"

    Means your trying to navigation from a page not wrapped in a NavigationPage.

    It's a common question.

    https://forums.xamarin.com/discussion/18590/how-to-work-around-pushasync-is-not-supported-globally-on-android

    Check out the template projects

    public async Task NavigateFromMenu(int id)
            {
                if (!MenuPages.ContainsKey(id))
                {
                    switch (id)
                    {
                        case (int)MenuItemType.Browse:
                            MenuPages.Add(id, new NavigationPage(new ItemsPage()));
                            break;
                        case (int)MenuItemType.About:
                            MenuPages.Add(id, new NavigationPage(new AboutPage()));
                            break;
                    }
                }
    
                var newPage = MenuPages[id];
    
                if (newPage != null && Detail != newPage)
                {
                    Detail = newPage;
    
                    if (Device.RuntimePlatform == Device.Android)
                        await Task.Delay(100);
    
                    IsPresented = false;
                }
            }
    
    
  • fsulserfsulser Member ✭✭
    edited February 27

    Thanks for the response. I already saw some question related to this.
    My problem is that if I'm doing whats usually suggested in those responses (setting MainPage = new NavigationPage(new MainPage()) in the App) adds a second navigation bar, which is not really the solution.
    For sure I could remove the default one and add a custom burger menu to the initial page and then use in the App the approach with the NavigationPage.
    But isn't there any better solution than that. Is there no possibility to use the template and just change the behaviour so if a menu-item is selected a new page opens and there is instead of the burger-menu a back-button?

  • NMackayNMackay GBInsider, University mod

    @fsulser said:
    Thanks for the response. I already saw some question related to this.
    My problem is that if I'm doing whats usually suggested in those responses (setting MainPage = new NavigationPage(new MainPage()) in the App) adds a second navigation bar, which is not really the solution.
    For sure I could remove the default one and add a custom burger menu to the initial page and then use in the App the approach with the NavigationPage.
    But isn't there any better solution than that. Is there no possibility to use the template and just change the behaviour so if a menu-item is selected a new page opens and there is instead of the burger-menu a back-button?

    You can do that but the behavior is a bit weird, you can still swipe left in Android and the Master popout page appears even though the back button is there and in UWP, the burger menu is always there. I generally navigate to a detail page and from the detail page you navigate modally and provide your own custom nav back to go back with TitleView.

    I might be missing your requirements but you could navigate to a modal stack and provide your own nav bar to go back.

  • fsulserfsulser Member ✭✭
    edited February 28
    Thank you again for the response.
    So the reason to have this is because I recohnized some inconsistant behaviour.
    If I select a button frome the mainpage and use the ’PushAsync’ then a user who would click on androids back-button would come back to the mainpage, and he also has the possibility to use the back button from the navigation bar.
    If the user now selects a menu-item, which opens the same page as the click on the mainpage, and hits androids back-button the app will close. This behaviour is kind of unexpected. The user instead should go back to the main-page and then I came up that it would be nice to have instead of the burger-menu a back button to be consistant.

    Building it manually shouldn't be a big problem but then I could not really make use of the template. But as the solution would be there with the possibility to use ’PushAsync’ from the menu I thought there would be an easier solution for this.
  • fsulserfsulser Member ✭✭

    @yelinzh said:
    There are two solutions to this issue.
    _1. Change code in the App.cs class as follows,

    MainPage = new NavigationPage(new PageA());
    

    _2. Add code in MainPage.xaml.cs , both the two line code are ok.
    The demo is from https://developer.xamarin.com/samples/xamarin-forms/Navigation/MasterDetailPage/

    //Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
    Detail.Navigation.PushAsync(new Page1());
    

    so the first is working, but produces a result which adds just a second navigation bar when using the Masterdetail template and that's not really usefull, see image:

    the second approach seems not to be adding a back button.

    I think simplest approach will be to use a basic template, push manually and add manually a burger menu to the main page. Then I should be able to pushasync and have the wanted behaviour.

  • yelinzhyelinzh Member, Xamarin Team Xamurai

    Adding the code in MainPage()'s constructor method can solve the problem appeared in first approach.

    NavigationPage.SetHasNavigationBar(this, false);
    
  • fsulserfsulser Member ✭✭
    edited February 28 Accepted Answer

    I tried now again the second approach and found a way, don't know why I wasn't able in the first try. Basically all what needs to be changed is something like shown in the snipped below in Mainpage in function NavigateFromMenu:

        public async Task NavigateFromMenu(int id)
        {
            switch (id)
            {
                   case (int)MenuItemType.Browse:
                        break;
                    case (int)MenuItemType.About:
                        PushPage(new AboutPage());
                        return;
            }
    
            var newPage = new NavigationPage(new HomePage());
            Detail = newPage;
    
            if (Device.RuntimePlatform == Device.Android)
                await Task.Delay(100);
    
            IsPresented = false;
        }
    
        public async void PushPage(ContentPage page)
        {
            await Detail.Navigation.PushAsync(page);
    
            if (Device.RuntimePlatform == Device.Android)
                await Task.Delay(100);
    
            IsPresented = false;
        }
    

    Just one remark, if the user clicks now on the Browse Item the main page will reload which is expected in my case.

    Thanks for the support

Sign In or Register to comment.