I’ve had an article published on the MSDN UK Team Blog, about Building a Windows Store app using Prism for the Windows Runtime. I’m reproducing the article on my blog as I’m going to build on it in a series of blog posts that will discuss different features of Prism.
Many of you will be familiar with Prism, a patterns & practices release that helps you to design and build composite applications. For the past 6 months I've been working with patterns & practices on the next evolution of Prism known as Prism for the Windows Runtime.
Prism for the Windows Runtime provides two libraries that help developers create managed Windows Store apps:
- The Microsoft.Practices.Prism.StoreApps library provides support for bootstrapping MVVM apps, state management, validation of user input, navigation, data binding, commands, Flyouts, settings, and search.
- The Microsoft.Practices.Prism.PubSubEvents Portable Class Library allows communication between loosely coupled components in an app, thus helping to reduce dependencies between assemblies in a Visual Studio solution.
Together the libraries accelerate development of apps by providing support for MVVM, loosely coupled communication, and the core services required in Windows Store apps.
Using Prism for the Windows Runtime
In order to demonstrate using Prism for the Windows Runtime, I've written a demo photo viewing app, which can be downloaded here. In the app, there are two pages. The first page presents a thumbnail gallery view of photos in the users Pictures library. Clicking on a thumbnail takes the user to the second page which displays the full image. In the app, support for MVVM, navigation, and state management are all provided by Prism for the Windows Runtime.
The first step in using Prism for the Windows Runtime is to add a reference to the Microsoft.Practices.Prism.StoreApps library to your project, in order to use the services provided by the library. The MvvmAppBase class provides core startup behaviour for an MVVM app, with its constructor being the entry point for the app. Your App class should then derive from the MvvmAppBase class, and adds app specific startup behaviour.
There are two view classes in the app, MainPage and PhotoPage, that bind to the MainPageViewModel and PhotoPageViewModel classes respectively. Each view class derives from the VisualStateAwarePage class, provided by the Prism.StoreApps library, that provides view management and navigation support. Each view model class derives from the ViewModel class, provided by the Prism.StoreApps library, that provides support for property change notification, navigation, and suspend/resume functionality. A static ViewModelLocator object, provided by the Prism.StoreApps library, is used to manage the instantiation of view models and their association to views.
A required override in the App class is the OnLaunchApplication method, from where you will typically perform your initial navigation to a launch page.
protected override void OnLaunchApplication(LaunchActivatedEventArgs args)
{
NavigationService.Navigate("Main", null);
}
This method uses the NavigationService, provided by the Prism.StoreApps library, to navigate to the MainPage in the app when it launches. "Main" is specified as the logical name of the view that will be navigated to. The default convention specified in the MvvmAppBase class is to append "Page" to the name and look for that page in a .Views child namespace in the project. Alternatively, another convention can be specified by overriding the GetPageType method in the MvvmAppBase class.
App specific initialization behaviour is specified in the OnInitialize method in the App class. In the case of the demo app this involves registering types and instances that will be used in the view model constructors with the Unity dependency injection container. However, Prism for the Windows Runtime is not dependent on Unity. Instead, you can register a factory with the ViewModelLocator object that will create a view model instance to be associated with a view. For more info see Using Prism for the Windows Runtime.
protected override void OnInitialize(IActivatedEventArgs args)
{
_container.RegisterInstance<INavigationService>(NavigationService);
_container.RegisterType<IRepository, FileSystemRepository>(new ContainerControlledLifetimeManager());
}
This method registers the NavigationService instance and FileSystemRepository type with the container, as singletons, based on their respective interfaces, so that the view model classes can take dependencies on them.
Because the demo app does use Unity, the Resolve method from the MvvmAppBase class is overridden in the App class to return a constructed view model instance.
protected override object Resolve(Type type)
{
return _container.Resolve(type);
}
This method override is used by the ViewModelLocator object to set a factory for the ViewModelLocator to use the container to construct view models so that their dependencies get injected by the container.
The ViewModelLocator object, provided by the Prism.StoreApps library, uses a convention-based approach to locate and instantiate view models from views. This convention assumes that view models are in the same assembly as the view types, that view models are in a .ViewModels child namespace, that views are in a .Views namespace, and that view model names correspond with view names and end with "ViewModel". The ViewModelLocator object has an attached property, AutoWireViewModel, which is used to manage the instantiation of view models and their association to views. In the view's XAML this attached property is set to true to indicate that the view model class should be automatically instantiated from the view class.
prism:ViewModelLocator.AutoWireViewModel="true"
The ViewModelLocator object uses the convention-based approach outlined earlier to resolve the correct view model type. The view model factory, set by the MvvmAppBase class, uses the dependency injection container to construct view model instances whose dependencies are injected by the container. When the view model instances are constructed, dependencies specified by the constructor parameters are resolved by the container and then passed into the view model. This is referred to as constructor injection. This approach removes the need for an object to locate its dependencies or manage their lifetimes, allows swapping of implemented dependencies without affecting the object, and facilitates testability by allowing dependencies to be mocked.
If you run the app and navigate to the PhotoPage, and then suspend and terminate the app, on activating the app again the previously loaded photo will be displayed. This is because the path to the photo is passed to PhotoPage as a navigation parameter, which is automatically serialized to disk by the Prism.StoreApps library when the app suspends. However, if you have any view model properties whose values you want to survive termination, you should annotate them with the [RestorableState] custom attribute. For more info see Handling suspend, resume, and activation.
Summary
Prism for the Windows Runtime can accelerate the development of Windows Store apps by providing support for MVVM, loosely coupled communication, and the core services required in Windows Store apps. For a bigger app that demonstrates all of the features of Prism for the Windows Runtime see Developing a Windows Store business app using C#, XAML, and Prism for the Windows Runtime.