[Xamarin.Forms 2.2.0] Wrapping MasterDetailPage inside NavigationPage

MihaiPirvuMihaiPirvu ROMember ✭✭

Hey guys!

I'm trying to do something I thought was rather simple. Before 2.2.0 I had the following code :

var mainPage = new MasterDetailPage
{
    MasterBehavior = MasterBehavior.Popover,
    Master = menuContentPage,
    Detail = detailsContentPage
};
var navigationPage = new NavigationPage(mainPage);
Application.Current.MainPage = mainPage;

The way I reason about this code is "create a NavigationPage with its navigation stack's first child being a MasterDetailPage, so that I can later push other pages on top of the entire MasterDetailpage.". In 2.1.x it used to work fine, on UWP at least (did not test Android / iOS). However, in 2.2.0, the hamburger menu toggle is missing (while working just fine on Android). After no luck with Google, I decided to look inside Charles Petzold's book (great work with this one, by the way!), and found this :

The MasterDetailPage.Master and MasterDetailPage.Detail property elements are set to in-stances of MasterPage and DetailPage, respectively, but with a little difference: The Detail prop-erty is set to a NavigationPage, and the x:Arguments tags specify the DetailPage as the construc-tor argument. This is necessary to enable the user interface that lets the user switch between the mas-ter and detail pages on the Universal Windows Platform.

So I tried that, and indeed it works! However, by doing this, I loose the functionality of pushing new pages on top of the MDP. I need this pages to act and feel "modal", so the user shouldn't have any access to the side menu. I've seen it behaving sort-of right on Android if I push on the NavigationPage wrapper for the details page, in the sense that the drawer turns into a back button, and I could indeed disable the swipe gesture in that case, but it's a messy workaround, and besides, by doing it like this on UWP, both the hamburger toggle and back button show up, which is not what I want.

So my question to you guys is how can I achieve this behaviour? (if even possible)

Note that I need to support Android, iOS and UWP.

Thank you!

Answers

  • ChaseFlorellChaseFlorell CAInsider, University mod

    try wrapping your Detail page in a NavigationPage

    Detail = new NavigationPage(detailPage);
    
  • MihaiPirvuMihaiPirvu ROMember ✭✭

    That does not produce the behaviour I need. On UWP I can still toggle the drawer from newly pushed pages on the NavigationPage stack. I want the user to be able to click "Back" from the pushed page, but not be able to access the side menu,

  • cahyoagungcahyoagung Member ✭✭

    2018 and still looking for this solution
    @MihaiPirvu have you found any solution for this?

  • MihaiPirvuMihaiPirvu ROMember ✭✭

    @cahyoagung said:
    2018 and still looking for this solution
    @MihaiPirvu have you found any solution for this?

    Not really. I haven't played around with this use case in some time, but I remember I ended up using a different NavigationPage on each tab + keeping track of each navigation stack, or something like that. I know it's not the ideal solution, but it was the closest workaround Forms could offer (aside from completely reimplementing everything via Custom Renderers, of course).

  • cahyoagungcahyoagung Member ✭✭

    @MihaiPirvu said:
    So I tried that, and indeed it works! However, by doing this, I loose the functionality of pushing new pages on top of the MDP. I need this pages to act and feel "modal", so the user shouldn't have any access to the side menu.

    For iOS and Android may be this approach can help us by setting IsGestureEnabled
    As docs said Has no effect on Windows Phone.

    Checking the NavigationStack if its items more than 1, set IsGestureEnable to false otherwise true. I have a function to show how it work

    private void EnableDisableSwipe() {
        var page = Application.Current.MainPage;
        if (page.GetType().IsSubclassOf(typeof(MasterDetailPage)) || page.GetType() == typeof(MasterDetailPage)) {
            var current = page as MasterDetailPage;
            var type = current.Detail.GetType();
            if (type.IsSubclassOf(typeof(NavigationPage)) || type == typeof(NavigationPage)) {
                var navPage = current.Detail as NavigationPage;
                if (navPage.Navigation.NavigationStack.Count <= 1)
                    current.IsGestureEnabled = true;
                else
                    current.IsGestureEnabled = false;
            }
        }
    }
    

    NOTE: always call the function after pushing or pulling any page

    public class ExtNavPage : NavigationPage {
        public ExtNavPage(Page page) : base(page) {
            Popped += NavEventHandle;
            PoppedToRoot += NavEventHandle;
            Pushed += NavEventHandle;
        }
    
        private void NavEventHandle(object sender, NavigationEventArgs e) {
            EnableDisableSwipe();
        }
    }
    
Sign In or Register to comment.