Exrin IMasterDetailContainer IsPresented has no effect, how to hide navigation drawer

60 views Asked by At

Context

I am using the ExrinSampleMobileApp from the Exrin repository. When I show the the navigation drawer with swipe, the drawer shows correctly. When I click on the Settings navigation, (after I corrected the MenuOperation to return new NavigationResult(Stacks.Main, Main.Settings); it navigates correctly, but the drawer remains on top.

I know that the Xamarin MasterDetailPage's IsPresented should be set false to hide the drawer. I also discovered that for this purpose there is an abstraction IMasterDetailContainer which provides a property (also called IsPresented) for this reason.

Question

However there are questions: Where and when to set this property to false and how to access it (I mean how to access to the IMasterDetailContainer implementor?)

After I can not figure out all the details and can not add the Completed Autofac builder the IMasterDetailContainer implementation, I decided to pass via a static reference just try if it works. Unfortunately does not, see the source code with comments:

// Note: This code from the otherwise unchanged ExrinSampleMobileApp from the Exrin repository
public class MenuOperation : ISingleOperation
{
    public static IMasterDetailContainer Mdc;
    private IMasterDetailContainer _masterDetailContainer;

    public MenuOperation(IMasterDetailContainer masterDetailContainer)
    {
        _masterDetailContainer = masterDetailContainer;
    }

    public Func<object, CancellationToken, Task<IList<IResult>>> Function
    {
        get
        {
            return (parameter, token) =>
            {
                // _masterDetailContainer = false
                // Shame, but no DI worked, so this is only for diagnostics (static):
                // This set really false, however the drawer remains and navigation freezed.
                Mdc.IsPresented = false;

                return new NavigationResult(Stacks.Main, Main.Settings);

                // Original navigation was:
                //return new NavigationResult(Containers.Main, Regions.Main, Stacks.Second, Second.Detail);
            };
        }
    }
2

There are 2 answers

1
Adam On

The best way I have found to do this, is to modify the NavigationProxy, on PushAsync and PopAsync. Replace them with this, and modify as necessary.

    public async Task PopAsync()
    {
        CloseMenu();

        await _page.PopAsync();         
    }

    public async Task PushAsync(object page)
    {
        var xamarinPage = page as Page;

        if (xamarinPage == null)
            throw new Exception("PushAsync can not push a non Xamarin Page");

        CloseMenu();

        await _page.PushAsync(xamarinPage, true);
    }

    private void CloseMenu()
    {
        if (Application.Current.MainPage is MasterDetailPage masterDetailPage)
            masterDetailPage.IsPresented = false;
    }
2
Timo Salomäki On

I'm not familiar with Exrin so there might be a better way to do this, but how about using the Messaging Center? You would get nice decoupling and could run a piece of code in the MainContainer to properly hide the menu from the MenuOperation class.

MenuOperation:

return (parameter, token) =>
{        
    // MainContainer will subscribe to this message and hide the drawer
    MessagingCenter.Send<MenuOperation> (this, "HideDrawer");

    return new NavigationResult(Stacks.Main, Main.Settings);

    ...

MainContainer:

public MainContainer(TabbedViewContainer mainStack, MenuStack menuStack) : base(Containers.Main.ToString())
{
    MessagingCenter.Subscribe<MenuOperation> (this, "HideDrawer", (sender) => 
    {
        IsPresented = false;
    }

    ...

I have also seen people save static references like you did, but on the App.xaml.cs file. However, that creates unnecessary complexitiy in my opinion.