0

I am struggling to understand how the PRISM INavigationService maps to the standard Navigation.PushAsync provided by Xamarin Forms.

I have an application that I have started using XF. It consists of a MasterDetailPage that is the home page and the "Detail" ContentPage contains a number of buttons that are used to then navigate to other functionality. Within the App.xaml.cs, I set the Application.MainPage to an instance of my home page wrapped within a NavigationPage "MainPage = new NavigationPage(new HomePage())". When I then want to display a functionality page, I call "Navigation.PushAsync(new NewPage())" and this shows the new page along with a toolbar containing a back button; I can then navigate back to my home page using either the back button on the device or using the back button in the toolbar. Note, the application is running on Android.

I then looked at integrating PRISM.Forms; I wanted to use this as I have used PRISM for WPF for many years and felt that it should prove beneficial. I am using the latest version (6.3).

I created a new application based upon the "PRISM Templates", and then replicated the differences into my existing project...

  • The "App" class is now based off of "PrismApplication" instead of "Application" Within "PrismApplication.RegisterTypes"
  • I call "Container.RegisterForNavigation" for all of the forms that I want to be able to navigate to At the end of "PrismApplication.OnInitialized"
  • I call "INavigationService.NavigateAsync($"/{nameof(NavigationPage)}/{nameof(HomeMasterDetailPage)}");"
  • Where I previously called "Navigation.PushAsync", I call "INavigationService.NavigateAsync(nameof(NewPage))" Within "MainActivity" I call the "App" constructor with an "IPlatformInitializer"

So far, so good. I see my home page as expected. However when I then navigate to "NewPage", I have no back button in the toolbar (though I still have my "hamburger" menu from the MasterDetailPage) and if I use the back button on the device it returns me to the operating system. It seems that the page has been inserted as the "Content" section of the MasterDetailPage instead of navigating to it as a new child page.

I am sure that this is not by design and therefore something that I am misunderstanding but can somebody point me back in the right direction as otherwise I feel I will have to discard PRISM and look at an alternative.

I also have a problem when trying to introduce a login screen into the mix. I start by calling "INavigationService.NavigateAsync($"/{nameof(NavigationPage)}/{nameof(LoginPage)}");" and then if login succeeds I call "INavigationService.NavigateAsync($"/{nameof(NavigationPage)}/{nameof(HomeMasterDetailPage)}");" to get to the home page; problem here is that when displaying the home page (a MasterDetailPage) I no longer see the "hamburger" button to open the "Master" portion of the page. I suspect that this is probably also related to my using the INavigationService incorrectly but if not I can raise it as a separate issue.

Martin Robins
  • 6,033
  • 10
  • 58
  • 95

1 Answers1

0

Prism's INavigationService essentially maps to the Xamarin Forms INavigation in this way: INavigationService.NavigateAsync => INavigation.PushAsync (or PushModalAsync if you set the useModal flag to true), & INavigationService.GoBackAsync => INavigation.PopAsync.

The INavigationService uses the container to resolve any pages that you specify in the Uri that you pass it and then pushes them onto the Navigation Stack. You may want to check out the various samples available, including the "HamburgerMenu" project which shows the use of a MasterDetailPage and it uses a LoginPage.

Dan Siegel
  • 5,724
  • 2
  • 14
  • 28
  • Thanks, that is kind of how I expected it to work but alas I cannot make it behave the way I want to. I think the problem is that as I am using a MasterDetailPage the INavigationService is setting the "Detail" page instead of calling PushAsync (I seem to recall reading about this somewhere but cannot find it now). If I can override this functionality I think it will solve my problem. – Martin Robins Apr 14 '17 at 11:32
  • Having reviewed the samples you referenced, I cannot find anything that matches with my scenario. What I am trying to achieve is the MasterDetailPage.Content being used as a main menu from which tapping an item navigates to a new page using PushAsync (instead of replacing the current "Detail" page) whilst the "Master" is an additional menu of options only available when the main menu is shown. All pages opened from the menu should show a back button and not the hamburger menu from the MasterDetailPage. – Martin Robins Apr 14 '17 at 11:53
  • Ok. Found what is happening; because I am navigating from a MasterDetailPage, the INavigationService.NavigateAsync is calling PageNavigationService.ProcessNavigationForMasterDetailPage (https://github.com/PrismLibrary/Prism/blob/master/Source/Xamarin/Prism.Forms/Navigation/PageNavigationService.cs#L298) which either calls PushModalAsync (via DoPush) or else replaces the current "Details" page - depending on the "useModalNavigation" parameter value. I see nothing within the code that will let me change the behaviour just using parameters. – Martin Robins Apr 14 '17 at 12:13
  • What it sounds like you are trying to do is simply have a hierarchical menu and navigate just within the Master only. Is this correct? –  Apr 14 '17 at 14:04
  • @BrianLagunas Not sure I understand your description but probably. I am looking to have a "login" page, that is followed by a "menu" page that also has a hamburger menu popout (hence my use of MasterDetailPage) and then allows me to navigate to other pages using PushAsync and the occasional PushModalAsync for popups. Each of the pages from the menu will also likely open further pages as we go along. – Martin Robins Apr 14 '17 at 15:04
  • Each of the PushAsync pages opened from the menu should have an action bar with a back button and will also likely open further pages as we go along. – Martin Robins Apr 14 '17 at 15:10
  • @BrianLagunas I guess what I am looking for is that some variation of the PushAsync/PushModelAsync/PopAsync be exposed directly as a part of the INavigationService as well as the NavigateAsync - but still allowing the use of your parameters. That then offers the developer the best of both worlds. So far it is just the special handling you have for the MasterDetailForm that is causing me a problem, but I suspect I could run into trouble with the TabbedPage too as you have deep linking in there too and I will probably want to be able to navigate on from there in the design I have been asked for. – Martin Robins Apr 14 '17 at 15:16
  • @BrianLagunas Sorry if my last comment was a little presumptuous in asking you to change your API, but I hope it can provide an insight as to the restrictions (as I see them) with the current functionality. Perhaps you would consider looking at these and seeing if there is something that you can do to allow such scenarios whilst maintaining your own design? – Martin Robins Apr 14 '17 at 15:24
  • Well, I'm not changing the API :). I guess the issue is that I don't really understand the problem. I think this might be related to how you have your app navigation/page setup. After a login you do an absolute navigation to reset the navigation stack. Then you have a master detail page as your new root. This is where you loose me. I have no idea what you are trying to do with a MasterDetailPage, but not update the detail. –  Apr 14 '17 at 16:20
  • Are you trying to navigate using PushAsync from the MMasterDetailPage, but not update the Detail, rather instead navigate to another page within a NavigationPage? Like this NavigationPage -> MasterDetailPage -> AnotherPage all wrapped in the root navigationPage? –  Apr 14 '17 at 16:29
  • If I'm understanding your description... You want a Menu that is based on the page that you're looking at. You might want to steer clear of MasterDetail and instead look at the Syncfusion `NavigationDrawer` or the Telerik `SideDrawer` – Dan Siegel Apr 14 '17 at 16:39
  • @BrianLagunas Yes; that sounds like what I want. Going back to Xamarin without PRISM, this would be MainPage=new NavigationPage(new MasterDetailPage)); and then within the MasterDetailPage it would be Navigation.PushAsync(new OtherPage());. "OtherPage" would not show the menu from the MasterDetailPage as it is not being opened as a replacement for the Detail section but is instead a new page in its own right and displays a back button. Is this possible with PRISM navigation? – Martin Robins Apr 15 '17 at 14:30
  • @DanS. Thanks, but I would prefer to stick with the MasterDetailPage; I have the flow that I want working with Xamarin, I am just trying to get the same flow with the PRISM INavigationService. If INavigationService does not offer what I want, I will simply not use it (but I am hoping that does not become the case). – Martin Robins Apr 15 '17 at 14:32
  • @MartinRobins actually, this is not a scenario that is handed currently. As you can see form the code we are only handling the modal navigation. I didn't think it was common, or recommended, to place a masterDetailPage in a NavigationPage. Can you submit an issue on the Prism site so that I can implement this behavior. It should be an easy fix. Good find! –  Apr 17 '17 at 14:15