Update March 13: Prism 7.0 is now live! While many of the concepts in this post still apply, please review the full set of changes on Brian Lagunas’ Blog. I’ve prepared a follow up post on how to upgrade your existing apps you can view here
Welcome! This is the second entry in a series where I explore MVVM frameworks that can be used with Xamarin.Forms. As a by-product of my investigation, I’ll have a handy bootstrapped project of each framework to help you get started using the framework discussed!
tl;dr – source code
Over the course of the series, I’ll be examining the pros and cons of the following MVVM Frameworks:
In this post, we’ll dive in to a framework that evolved from Microsoft Patterns & Practices. Prism 6 is now fully open source and has formed a very robust following which has led to a lot of great tutorials and presentations, like this one by Brian Lagunas from Evolve 2016. Its a great watch, so I won’t judge if you’d rather follow along with a vid. That said, if you prefer reading or forgot your headphones at home, I’ll dive into some of the neat MVVM features that comes with Prism.Forms in this blog post and help you create your first project using Prism.
It always starts with a NuGet package. Using the NuGet package explorer, a quick search for “Prism.Forms” is likely to yield the library you need. Don’t forget! You’ll need to add the package and any dependencies to each project; your PCL, and every platform you are supporting. Of course, you can always get it from the command line package manager, if you prefer, like so:
Install-Package Prism.Forms -Version 7.1.0
Prism also provides a template pack, which makes setting up your Views and ViewModels. On Visual Studio for Mac. Check out the documentation on GitHub to get it set up for Visual Studio on Mac or Windows – I highly recommend the template pack, but for the sake of rigor this post will assume the extension hasn’t been installed.
Like in the previous, MVVMLight sample, let’s configure our folder structure to be more MVVM-like once the needed packages are done installing. The final result will look something like this:
For the sake of consistency, we will try to keep the structure and content as similar to the previous entry in this series as possible. As with the MvvmLight demonstration, let’s delete the default HomePage.xaml and create a new one within our Views folder, as well as a few other pages. Notice right away that we no longer need the startup folder or the contents within: IoCConfig and ViewModelLocator. Thats because the functions handled by those classes are now part of the base class PrismApplication, which our main App.cs needs to inherit from. So, we make a quick change to the App.xaml.cs and App.xaml (if we have it), such that the xaml looks like so:
… and App inherits PrismApplication as well:
There are some abstract methods we need to implement to make the compiler happy, so let’s go ahead and build those out with some things we know will be needed down the line, such as registering our Views and setting a root page.
Unless you have a single page application, be sure to include a NavigationPage in your initial stack. Here’s what this looks like in our case, where we’re utilizing the Master Detail layout:
The navigation service for Prism (which comes fully built out of the box, a huge leg up over MvvmLight IMO), treats navigation and the navigation stack . much like a web URL. As pages are added and we traverse deeper into the stack, the “URL” that describes the stack gets longer. What we are doing in the OnInitialized() method takes advantage of this fact to specify the root view (a Master/Detail page we named “Root”), set the Navigation Page on the Detail view and set the Detail View page (our Home Page from before). This is especially useful for “deep linking” – your starting view is entirely dependent on what string URL the NavigationService is passed, we can be driven by push notifications, web links, or any other avenue of entry to the app that may require a specific landing point. For this simple example however, once we’ve finished configuring our Views and ViewModels, the end result will be nearly indistinguishable from the previous example.
Let’s start with AppShell.xaml and tell our View about the ViewModel that backs it:
Assuming you have the Prism Template Pack, the highlighted lines will be added for you. But, there is no harm in adding them by hand as I have done. Notice that we are relying on Prism to “Auto Wire” the View to it’s ViewModel. Because of this, we need to make sure that our Views and ViewModels follow very specific naming conventions. For example, if we create a page called HomePage.xaml, it’s ViewModel must be named HomePageViewModel. You can define your own mappings manually, but I prefer to rely on the Prism’s auto wire function, as it happens to conform to my usual MVVM naming habits. Since we are using a Master/Detail view, we need to add some stuff in the code behind of App.xaml.cs:
Here we implement a few Prism interfaces to expose Master/Detail functionality; namely, closing the menu on navigation which we achieved previously using Messaging. With that in mind, we can follow suit and add the View/ViewModel relationship to our remaining pages.
From the perspective of the View, commanding in Prism is nearly identical to our previous example in the series. In fact, beyond the initial establishment of data context, you can essentially copy/paste the previous example directly into this new project file.
That said, things do look a little different from the ViewModel, but a similar pattern follows. We establish our command like so:
ShowAlertCommand = new DelegateCommand(async () => await ShowAlert());
ShowActionSheetCommand = new DelegateCommand(async () => await ShowActionSheet());
SelectItemCommand = new DelegateCommand<CopyItem>((param) => Navigate(param));
Unlike before, we are using DelegateCommands rather than RelayCommands, but the end result is the same – we have successfully bound ViewModel logic to the view that the user can interact with.
We already touched on Prism’s cool URL-like navigation schema, but let’s look a little more at that in practice. Like before, we’ll need to inject our navigation and dialog services into the constructor of our ViewModel. Unlike before, however, both services already have implementations we can utilize right from Prism.Forms:
public HomePageViewModel(IPageDialogService dialogService, INavigationService navigationService) : base(navigationService)
this.Title = “Home”;
_dialogService = dialogService;
Then we can start navigating from our ViewModel; the simplest means is to simple provide the name of the View we wish to navigate to, like so:
If, for example, we want to pass parameters, we can achieve that by providing query string “properties” to the navigation URI, which we then retrieve on the result page. Thus, from our calling page we would form out navigation URI like so:
And use the following code block on the next page by overriding the OnNavigatedTo method that is part of the INavigationAware interface:
public override void OnNavigatedTo(INavigationParameters parameters)
this.Copy = parameters.GetValue<string>(“content”);
this.Subject = parameters.GetValue<string>(“subject”);
For a more complex objects, we could also initialize our Navigation Parameters using a strongly-typed object, like so:
Using the URI scheme provided by Prism, we can also easily reset the root page of our app by providing an absolute URI. This is especially useful in scenarios like when a user is signing in or out of our app:
Also note that we can replace the previous page (or series of pages, using this syntax:
await _navigationService.NavigateAsync($”../PageToReplacePrevious”); // replace previous
await _navigationService.NavigateAsync($”../../PageToReplacePrevious”); // replace two previous
Show Alerts & Dialogs
Like navigating, getting user interaction using MVVM can be a bit confusing at first. In many cases, we may want to present the user with an alert dialog (such as when an error occurs, or when the app needs user confirmation), or an action sheet (such as when the app should present the user with many options).
Using Prism.Forms, the dialog service is already implemented for us; we just need to get a reference to IPageDialogService, which we injected earlier in our constructor. Once we have that reference, we can start showing dialogs! Prism.Forms provides two flavors of alert dialogs we can use – one with “accept only” buttons, and one with “confirm or deny” buttons and you can control the text displayed in either case. Let’s see what using the latter looks like:
We also have Action Sheets taken care of for us:
We did it! That concludes our tour of Prism in Xamarin.Forms. If you’re still craving Prism.Forms goodies, the GitHub repo has a bunch of spectacular samples specifically for Xamarin.Forms, and the documentation is top notch. For the example used in this post, feel free to browse the complete source code, or leave a comment if you have questions!