1

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);
            };
        }
    }
Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
g.pickardou
  • 32,346
  • 36
  • 123
  • 268

2 Answers2

1

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.

Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
  • Many thanks. I am dealing with two problems, first how to access to the property, secondly if I can access, still does not work as expected. The static thing was only to try "if I can access, then what it does", and temporary untily I find out the DI access – g.pickardou Sep 19 '17 at 21:06
  • I have something... it's the usual UI thread thing. Setting that property is allowed only in the UI thread, unless strange things happen... (Device.BeginInvokeOnMainThread) – g.pickardou Sep 19 '17 at 22:13
1

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;
    }
Adam
  • 16,089
  • 6
  • 66
  • 109
  • Many thanks for the help. I've already discovered NavigationProxy as a potencial interception point, however unfortunately, when the user navigates to a particular page, then using the menu picks the very same menu item, no navigation occurs, so no interception occur. I have a backup plan, to override Func, Task> HandleResult in MenuViewModel, and marshalling the IsPresent = false to the main UI thread. (or better: marshalling the proxy property setter in MainContainer) However accessing to IMasterDetailContainer sill remains the question, DI does not play here... – g.pickardou Sep 20 '17 at 05:33