Jerry Nixon @Work: Let’s Code! Strongly-typed Experiences in Prism MVVM for Windows Store

Jerry Nixon on Windows

Monday, August 11, 2014

Let’s Code! Strongly-typed Experiences in Prism MVVM for Windows Store

imageMicrosoft Patterns and Practices has created Prism MVVM for Windows Store Apps. This lightweight framework/toolkit gives you what you would get with MVVM Light but with some helper classes specific to Windows Store Apps – like app lifecycle management, extended splash screen, and orientation detection. 

Navigation Service

One key to Prism and every MVVM framework is the Navigation Service. Prism’s Navigation Service has a Navigate(string, object) method into which you do not pass the page type, no. You pass the Experience.

Application Experience

What exactly is an experience? Think of an exper4ience as the name of the container for a page and view model. You might have a “login” experience – this would include a Views.LoginPage and ViewModels.LoginPageViewModel. You might have a “main” experience – this would include Views.MainPage and ViewModels.MainPageViewModel.

Here’s how you might visualize it:

Picture1

Let me say it again. An experience is the string description of the combination of a view and view model. This removes the need for the view model to have a reference to the view. It also removes the need of the view to have a reference to the view model. In either case, it’s different and takes about 20 seconds to reprogram your brain to think about it like this instead of as hard types.

Note: Why didn’t the native Windows Store framework do it this way? I am not sure; I believe it should have. I think I could have easily explained it to developers. And, I think (just like ASP.Net MVC) convention simplifies.

Getting the Navigation Service

Before you can navigate, you will need Prism’s Navigation Service. It’s a pretty simplistic thing. Prism wants App.xaml.cs to inherit from MvvmAppBase instead of Application. This simplifies App.xaml.cs a ton – it removes most of the stupid, confusing boilerplate code. Then, NavigationService is a protected property of MvvmAppBase. Then as a developer you expose it or put it into an IoC container.

Navigation Syntax

Typical Store navigation (using Navigate() off the Frame) navigates to a type. So, you you might assume: “Navigate(typeof(Views.MainPage))”, but that’s not correct. The Prism Navigation Service takes a string.

So, you might assume: “Navigate(‘MainPage’)”, but that’s not correct. The reason it is not correct is because you are not asking to Navigate to a page, like the native Frame object’s Navigate() method does. No. Remember, you are asking the service to navigate to an Experience. You can’t ask to navigate to a view because you may not have reference to it from the scope where you are calling. But a string works. A string doesn’t have a scope.

What’s the convention?

The Prism Navigation Service will find the corresponding page and view model for the experience you express. How? Though convention. It looks in the Views namespace for {expeirence}Page and looing in the ViewModels namespace for {Experience}[Page]ViewModel. If those conventions don’t work for you, then you can change them. That’s just how they are out-of-the-box.

As a result, you can create a MainPage and a MainPageViewModel and let them be bound by the Navigation Service. It also means you can move views and models around in different folders or projects and the remain connected as you update the service to look in the correct location. No other code need change.

How to type it?

The problem is, I hate literal strings. Sometimes, I know, they are a necessary evil. But if I can work around them, I prefer to. In order to do that, I only need to use an enumeration. And, if I expose my own wrapper for the Navigation Service, I can enforce the correct usage of the enumeration.

Look at this:

image

In the code above, we create an Experiences enumeration that locks in the strongly typed representations of the app experiences. In this case, there’s only Login, Main and Detail. No problem. I’d add more if I need them.

Note: the Experiences enumeration is next to the interface. This is because if you ever try to break apart your app to separate projects for sharing and testing your code, your interfaces will likely be in scope everywhere. Of course, you can put this anywhere that best fits your app project approach.

Then, I create my own custom interface (INavigationService) for the Navigation Service. I’ll use this if my app happens to use dependency injection. Then, my class (NavigationService) implements my custom Navigate() method. If I need more methods (like GoBack()) I would add those.

How to get it out of App.xaml.cs

Finally, I let a static reference to the Prism Navigation Service reside in a protected property. I make that property write-only so that I can use it internally and write from it from the App.xaml.cs when the app loads and while the Navigation Service is in scope.

It looks like this:

image

It’s as easy as that. And, if you aren’t using a container for dependency injection, then you don’t even need to use that second line there. It’s important to remember that NavigationService is a property off MvvmAppBase, but it is protected. This means it is not in scope for the rest of the app if you don’t expose it in some way (like we are here).

Conclusion

I’m not changing how Prism MVVM works. Prism MVVM is a lightweight way to handle navigation in a XAML application. But since the Navigation Service takes a string in as a parameter, and since I seriously do not like literal strings (at an OCD-level), this small customization allows me to use an enumeration to navigate from one Experience to another. Simple as that.

Here’s more information on Prism MVVM for Windows Store Universal Apps.

Best of luck!