Back in March I released the first preview of Prism for Xamarin.Forms.  Since then, there has been a ton of great feedback from the Xamarin community.  Today, I am happy to announce the next evolution of Prism for Xamarin.Forms available now on NuGet as a preview (6.1.0-pre1).  Of course, you don’t use Prism for Xamarin.Forms alone, you must have a dependency container to use with it.  With this preview we have support for the following containers:

Now, you may be asking yourself what’s new in this latest preview.  Well, the navigation has been completely overhauled and the bootstrapping process has slightly changed to support more complex startup scenarios like deep linking (I’ll get to that later).

A New Bootstrapping Process

The first release of the bootstrapping process has some limitations with application startup and integrating with the INavigationAware OnNavigatedTo and OnNavigatedFrom methods.  This was because the original bootstrapper didn’t rely on the INavigationService to set the application’s MainPage.  It was also very limiting on how you set the MainPage to other page type such as a MasterDetail, TabbedPage, or NavigationPage.  For example; how would you set the MainPage to a MasterDetail, and then immediately navigate to a different view as the Detail at startup?

I am happy to say that this has been fixed.  The original CreateMainPage and InitializeShell methods have been marked as obsolete.  Instead, you now override the OnInitialized method and navigate to the MainPage as you would any other page in your application using the new NavigationService property located in the bootstrapper.  This is what your bootstrapper will look like now:

public class Bootstrapper : UnityBootstrapper
{
    protected override void OnInitialized()
    {
        NavigationService.Navigate("MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>();
    }
}

As you can see, you simply register your page for navigation like you normally would, but now you simply specify which page to navigate to in the OnInitialized method.  This gives you a lot more flexibility on how you navigate when you first launch the app, as well as gives you the ability to pass parameters to your views during startup.

An Improved Navigation Service

Probably the biggest improvement in the 6.2.0 preview is the complete rewrite of the INavigationService.  The INavigationService now has support for URI based navigation, deep linking while maintaining the navigation stack, and passing parameters via the GoBack method call.  Let’s talk about each of these.

URI Based Navigation

The first improvement we made was the ability to support both relative and absolute URI’s for navigation.  This means that you can use an HTTP, or custom, protocol to dynamically create navigation links.  For example:

//relative
_navigationService.Navigate(new Uri("MainPage", UriKind.Relative));

//absolute
_navigationService.Navigate(new Uri("http://www.brianlagunas.com/MainPage", UriKind.Absolute));

Deep Linking

This is probably the best feature yet!  We worked very hard to make the INavigationService as smart as it can possibly be.  The INavigationService now automatically handles navigation automatically no matter where you call Navigate from.  The INavigationService will detect the type of page you are navigating from and automatically handle the navigation for you.  So if you are navigating from a MasterDetail, it will know that and set the MasterDetail.Detail property to your target view instead of navigating modally.  Are you navigating from a NavigationPage?  Don’t worry about setting that silly UseModalNavigation parameter again!  The INavigationService will know where you are navigating from and handle the PushAsync call for you.  This goes for TabbedPages, CarouselPages, MasterDetailPages, NavigationPages, and regular ContentPages.

So how does this all work?  Deep linking!  Let’s say that you want to navigate to a MasterDetailPage, then set the Detail to a NavigationPage, and then PushAsync to a COntentPage, and then PsuhAsync to a TabbedPage while selecting the second tab on that page.  How on earth would you do that with Prism, and from within your ViewModel?  Easy!

First, you have to make sure you register all your pages with the navigation service.

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<MyNavigationPage>();
    Container.RegisterTypeForNavigation<MyTabbedPage>();
    Container.RegisterTypeForNavigation<MyMasterDetail>();
    Container.RegisterTypeForNavigation<ViewA>();
    Container.RegisterTypeForNavigation<ViewB>();
    Container.RegisterTypeForNavigation<ViewC>();
}

Then you simply build up your navigation stack like so:

_navigationService.Navigate(“MyMasterDetail/MyNavigationPage/ViewA/MyTabbedPage/ViewB”);

Pretty slick right!  The result of this navigation will show the TabbedPage with the second tab selected (ViewB).  Your back stack will be just as you expect it to be as you use the hardware button, software button, or call GoBack on the INavigationService to navigate backwards.  This gives you the ultimate control in navigation and takes all the work out of managing your more complex navigation scenarios all from within your nicely testable ViewModel.

Now image this when you start your application.  You can now launch your Xamarin.Forms applications from a website and deep link to content within your app al while maintaining a proper back stack.

Passing Parameters

But Brian, what about parameters?  I’m glad you asked.  The parameter function in the newest preview of Prism for Xamarin.Forms is unlike anything you have ever seen out of any framework.  Sure we support the simple scenarios of passing parameters via the INavigationService parameter option like this:

_navigationService.Navigate(“MainPage”, myNavigationParameters);

Since we support URI based navigation, we also support URI based parameters too.  So now you can do this:

_navigationService.Navigate(“MainPage?id=5&name=Brian”);

Pretty slick right?  Well what if you have some parameters that are URI based, and others that are generated by your code that need ot be passed in?  No problem.  Just use both:

_navigationService.Navigate(“MainPage?id=5&name=Brian”, myNavigationParameters);

This will take the URI based parameters and the NavigationParameters, and combine them into a single set of parameters that can be used by your target ViewModels.  Alright Brian, that looks very cool.  But, what about passing parameters during deep linking scenarios?  Prepare to have your mind blown:

_navigationService.Navigate(“MyMasterDetail?id=1/MyNavigationPage?id=37/ViewA?fname=brian&lname=lagunas/ViewB?id=B”);

Now pick your brains up off the floor, and scrap them off the walls!  You can easily pass page specific parameters during deep linking navigation simply by providing the URI based parameters with the target page.

Breaking Changes

So not everything is going to go smooth with your upgrade.  I do have a couple of breaking changes to discuss.  Due to feedback from the community, and the complete rewrite to the INavigationService, I had to remove the following objects:

  • INavigationPageProvider
  • NavigationPageProviderAttribute

The objects allowed you to wrap the target page into another page type, like a NavigationPage, during a navigation process.  Since the INavigationService is now smart enough to handle most navigation scenarios, this isn’t really needed anymore.  Though, I would like to know the community’s thoughts on this.  Maybe you don’t need to replace the page anymore, but maybe you still want to do some page setup, or initialization before the navigation completes?  I don’t know.  So I need your feedback on this.  Maybe we add something closer to an IPageFormatter that allows you to do this instead.  You guys have to let me know what you need.

Summary

I hope you are as excited as I am about the latest Prism for Xamarin.Forms preview release.  I wanted to get this preview out to the community as quickly as possible in order to get your feedback on the direction Prism for Xamarin.Forms is going.  Let me know what you think about the API.  Tell me what sucks, but better yet, tell me what is great.  If you have an idea that you would like to see implemented, be sure to fork our repository and submit a pull request.

As always, feel free contact me on my blog, connect with me on Twitter (@brianlagunas), or leave a comment below for any questions or comments you may have.

Brian Lagunas

View all posts

20 comments

  • Dear Brian,

    Do you have any plan to implement this very usefull navigation service feature in WPF platform?
    I (and I think lot more) very appriciate this.

    József

    • Not at the moment. Since region navigations is completely different than a page based navigation system, a lot of thought would have to go into a WPF version of this. Maybe we can look at this later down the road.

  • Brian,

    Awesome work! I’m switching over to this version since we’re a few months from release anyway and this has all of the things I had hoped you could do in it. So a huge thanks!

    As I’m implementing this it looks like we don’t need to run the bs.run() like in the old. Seems you’ve got it to run it’s Initialize routine without having to call it somehow…I’ve not looked into the new code yet so I’ve not looked at how you pulled that off. But what I am seeing is that it’s firing the Initialize routine prior to the App constructor. In our app I’ve switched it to using and app.xaml.cs and and app.xaml file so I can have an app wide resource dictionary for styles and such. What I’m seeing happening is that the InitializeComponent() in the app constructor fires off after the bootstrapper’s OnInitialize runs which navigates to a page that requires a style in the app.xaml. End result being it can’t find the style since it navigated to the page prior to the the apps InitializeComponent running.

    Now I can totally hacky get around that by doing this:

    public class Bootstrapper : PrismApplication
    {
    private int timesrun = 0;
    protected async override void OnInitialized()
    {
    if (timesrun != 0)
    {do work}
    timesrun++}
    }

    and then call bs.Initialize(); after InitializeComponent(); in the app.xaml.cs file. So that seems to verify things are running out of order, but it’s not the prettiest solution ever. 🙂

    I’ll copy this to the issues page as well. But figured I’d post here in case someone wants to play around with the latest stuff and needs a temporary hack to get around the problem.

    As always thanks for your amazing work.

    Jeff

  • I’m implementing this it looks like we don’t need to run the bs.run() like in the old. Seems you’ve got it to run it’s Initialize routine without having to call it somehow! Amazing work!

  • Hi,

    First of all thanks for PRISM! It is really great!

    I have a question regarding new INavigationService. I have implemented a MasterDetailPage (created based on: https://developer.xamarin.com/guides/xamarin-forms/user-interface/navigation/master-detail-page/), and used INavigationService just like you described. It is working! But changing pages doesn’t change NavigationBar Title ;(
    I am new to both PRISM and Xamarin. My guess is that it is because NavigationPage, but without it, there is always application name in NavigationBar. But maybe I am doing something wrong?

    I will appreciate any help, as this is my university project 😉

    • Well, the back button is different on each platform. If you are expecting to change the MasterDetail.Detail page multiple times and then have the back button go back through the order of navigation, it won’t. That’s not how MasterDetail works. MsterDetail only changed the Details page and does not add any pages to the navigation stack.

      If you are just trying to show a header in a NavigationPage, then you have to set the properties on the page you are navigating to.

  • I am not using the hardware back button at all. I use buttons in MasterPage using INavigationService Navigate command.

    I would like to add NavigationPage inside DetailPage so that I can see title of the ContentPage that is displaying. In Xamarin Example it is done like this:

    Then after starting an app everything looks perfect: http://1drv.ms/1Ocg0HS
    But after using button in Master to change the page to different one (server in my case), title bar doesn’t change: http://1drv.ms/1Ocg5v7

    If I get rid of NavigationPage:

    There is always application name (“Projekt indywidualny”) in title bar (or no title at all on iOS device):
    http://1drv.ms/1nbh8CO
    http://1drv.ms/1nbhbOV

    • If you want to have the DetaiPage to always be a NavigationPage and only navigate within the NavigationPage without updating to a new Detail, then you need to bind your Master navigation buttons to the Detail page’s navigation service. In your case since you want to use a NavigationPage, then it would be the NavigationPage’s CurrentPage property. So you would need something like this:

      Button Text="ViewA" BindingContext="{x:Reference masterDetail}" Command="{Binding Detail.CurrentPage.BindingContext.NavigateCommand}" CommandParameter="ViewA?id=A"

      This is using the Detail as the source of the navigation call and will properly navigate various pages within the NavigationPage being used as the Detail.

      For controlling titles, you need to refer to Xamarin’s documentation because Prism doesn’t do anything with titles.

  • Thank you for your reply. It is working right now and as navigation service changes page inside NavigationPage correctly title changes also work great!
    Thanks a lot for help!
    The only problem is that now Master doesn’t hide automatically, but I think I will be able to find a solution on my own.

    • Yeah, you are no longer navigating off of the MasterDetail, but rather the Detail page instead. So it doesn’t know to close the drawer. All you have to do is add an event handler for the click event to manually close it. Easy fix.

  • Great work Brian – just a quick question, I’m just looking into Xamarin and would like to combine this with Prism. I wanted to know if Prism’s NavigationService is fully compatible with Xamarin’s navigation mechanism – i.e with respect to say iOS’s default navigation stack and default rendering of the ‘ <' back icon ?

    Thus, when a Page is pushed onto the stack, and if you create your main page with :

    new NavigationPage(MyPage)

    and MyPage has a button that runs a DelegateCommand from the ViewModel which uses the INavigationService – to call a new Page – Page 2 , will :

    Page2 be shown as the main page and a default < be rendered automatically ?

    So what I'm asking – is the NavigationService in prism 6.2 fully compatible with existing functionality and rendering of what we currently get in Xamarin Forms ?

    I couldnt see any examples on whether this was possible.

    • Yes. The Prism INavigationService is built on top of Xamarin.Forms navigation framework. All Prism does is abstract away all the hard coded Page classes and instances away from code-behind, and into a ViewModel friendly navigation service. The INavigationService tries to be smart about what type of page you are navigating from and to, and makes decisions based on that information. As you know navigation can be very complex in XF apps, and Prims makes this as simple as possible to do from a VM.

  • Thanks for coming back so quick – I’ve knocked up a simple Xamarin forms app just to see if Prism is suitable for our purpose.

    Have a MyMenuPage with 5 buttons , each delegating to a DelegateCommand that sits being MyMenuPageViewModel.

    The navigate functionality is :

    // Navigate from MainPage item, where item one of :
    // P1
    // P2
    // P3
    // P4
    // P5
    private void Navigate(String item )
    {
    _navigationService.Navigate(item);
    }

    inside my derived class of UnityBootstrapper, I register VM’s and Views that need to participate in navigation , namely :

    protected override void RegisterTypes()
    {

    .. Register View Models …

    Container.RegisterTypeForNavigation(“P1”);
    Container.RegisterTypeForNavigation(“P2”);
    Container.RegisterTypeForNavigation(“P3”);
    Container.RegisterTypeForNavigation(“P4”);
    Container.RegisterTypeForNavigation(“P5”);

    }

    Finally, application is started via a :

    this.App.MainPage = new NavigationPage(new MyMenuPage())

    Everything works in terms of MyMenuPage being displayed with 5 buttons, and clicking on each button navigates correctly – however, I do not get any BACK chevron ‘<' (Testing under iOS) nor do I get the name of the page (Page1, Page 2 etc) being shown at the top of the navigation bar. So my question Is – Is this functionality suppose to be provided by the Prism's Navigation service ?

    Note – All Pages, Page1-Page5 are just XAML forms with a ContentPage and a Label denoting the Page.

    • First off, you don’t set the Application.MainPage anymore. As mentioned in this post, you need to just use the NavigationService in OnInitialized. You will have to have a NavigationPage defined too. Also, I am not usre if this preview has the updated navigation logic to automatically detect the parent page. Try calling Navigate(useModalNavigation=false) and see what happens. The lates code base has a ton of improvemtns. I will try to get a Preview 3 out as soon as I can.

  • I’m having unexpected behavior whilst running the latest pre release.

    If I implement INavagationAware, the method –

    public void OnNavigatedFrom(NavigationParameters parameters)

    never gets called when I set useModalNavigation=false. OnNavigateTo does get called on entry to the ViewModel. Is there another interface that needs implementing with this new release that allows notification of when the user navigates away from a view model – if useModalNavigation is left as default, navigation in terms of Back button and Title does not get displayed.

  • Will Prism support other platforms of Xamarin like Xamarin.Mac, Apple Watch, Android Wear, TVOS, etc in future?

Follow Me

Follow me on Twitter, subscribe to my YouTube channel, and watch me stream live on Twitch.