Friday, November 14, 2014

Using Prism for Windows Runtime

I have been spending some tremendously quality time with Prism for the Windows Runtime and thought of writing this post in which I am going show you how you can include Prism for Windows Runtime in your Windows Runtime app.

Now you must be wondering what is Prism for Windows Runtime and why should I use it in my application. I had the same question when I started off with Prism for Windows Runtime and trust me, once you learn about Prism for Window Runtime, you definitely will think about restructuring all of your previous Windows Runtime apps to include Prism.

Let’s start off with an introduction to Prism for Windows Runtime.

Prism for Windows Runtime


Prism for Windows Runtime was developed by Microsoft Patterns & Practices Team (the same team who developed Enterprise Library). If you have been doing WPF/Silverlight, there is Prism for WPF which is widely used and popular among the developers. So basically what Prism does is, it is a framework providing set of guidelines and functionalities for you to develop large scale applications which is flexible, loosely coupled, easily maintainable etc. It does this by applying various practices like dependency injection, MVVM, Messaging etc. through out the project.

Prism for Windows Runtime is (as the name suggests) mainly for Windows Runtime apps which are Windows 8.1 apps and Windows Phone 8.1 apps. It has nothing to do with Prism for WPF. Since this lightweight framework targets Windows Runtime, it abstracts most of the code for state management,  navigation etc. in their base classes, so developers can totally focus on business logic. When we go through the demo, you will see that how Prism simplifies tones of boilerplate code in App.xaml.cs.

Now let’s see Prism for Windows Runtime in action. To implement Prism, you need to follow below set of rules.

As I mentioned before Prism uses it’s own Navigation Service. For that Views use ViewModelLocator.AutoWireViewModel. In simple what this does is based on the Views and ViewModels name it finds associated ViewModel to the View and do the binding on the runtime. For design time binding it uses d:Page.DataContext property in the XAML.

Now let’s start. I am creating a blank Windows App.

image
Blank App
Now I am adding Prism for Windows Runtime by running following command in Package Manager Console.
Install-Package Prism.StoreApps

Once the command got executed successfully, let’s modify the App.xaml.cs first. I am going to remove all the boilerplate code inside App class. Instead of deriving from Application, I am going to derive from MvvmAppBase as follows.
namespace PrismForWinRTDemo
{
    sealed partial class App : MvvmAppBase
    {
        
    }
}
Then let’s go to designer of App.xaml and modify it as follows.
<prism:MvvmAppBase
    x:Class="PrismForWinRTDemo.App"
    xmlns:prism="using:Microsoft.Practices.Prism.Mvvm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PrismForWinRTDemo">
 
</prism:MvvmAppBase>

image
App.xaml
So here first I have added a xml namespace to Prism MVVM (it’s where MvvmAppBase is located) and instead of Application, I have changed the page base to MvvmAppBase.

Moving back to the App.xaml.cs, here in MvvmAppBase, there is this abstract method “OnLaunchApplicationAsync” which you really must implement. So let’s add it.
sealed partial class App : MvvmAppBase
{
    public App()
    {
        this.InitializeComponent();
    }
 
    protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
    {
        return Task.FromResult<object>(null);
    }
}
Since, “OnLaunchApplicationAsync” expects a Task to be returned, I am returning an empty task. Let’s keep it as it is for now and let’s proceed.

Now let’s create a folder named “Views” and move defaulty created MainPage to the Views folder (remember to update the namespace accordingly after moving). Then I am modifying the MainPage.xaml.cs as follows. Here my MainPage is inheriting from VisualStateAwarePage. If you have a look at the implementation of VisualStateAwarePage, it’s inheriting from Page and implementing IView.
namespace PrismForWinRTDemo.Views
{
    public sealed partial class MainPage : VisualStateAwarePage
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
    }
}
Let’s modify the designer as well.
<storeapp:VisualStateAwarePage
    x:Class="PrismForWinRTDemo.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:storeapp="using:Microsoft.Practices.Prism.StoreApps"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PrismForWinRTDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        
    </Grid>
</storeapp:VisualStateAwarePage>

image
MainPage.xaml
Here instead of basing on Page, the view is now based VisualStateAwarePage which is available in Microsoft.Practices.Prism.StoreApps namespace.

Now I am creating a folder named “Interfaces” and creating an interface named “IMainPageViewModel” which exposes two string properties.
namespace PrismForWinRTDemo.Interfaces
{
    public interface IMainPageViewModel
    {
        string FirstName { get; set; }
 
        string LastName { get; set; }
    }
}
Now let’s add a folder named “ViewModels” and add the “MainPageViewModel” class which inherit from the ViewModel and implements IMainPageViewModel.
namespace PrismForWinRTDemo.ViewModels
{
    public class MainPageViewModel : ViewModel, IMainPageViewModel
    {

    }
}
Once the class is added, I am going to modify it further. I am adding two properties (which are FirstName and LastName) and I am overriding the OnNavigatedTo in ViewModel (in prism, viewmodel has OnNavigatedTo/OnNavigatedFrom events), where I am going to set some values for my declared properties.
public class MainPageViewModel : ViewModel, IMainPageViewModel
{
    private string firstName;
    public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            SetProperty(ref firstName, value);
        }
    }
 
    private string lastName;
    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            SetProperty(ref lastName, value);
        }
    }
 
    public override void OnNavigatedTo(object navigationParameter, NavigationMode navigationMode, Dictionary<string, object> viewModelState)
    {
        this.FirstName = "Jaliya";
        this.LastName = "Udagedara";
    }
}
Here since the ViewModel inherits from BindableBase (BindableBase is a Implementation of INotifyPropertyChanged to simplify models), I don’t want to implement INotifyPropertyChanged in MainPageViewModel. Instead SetProperty method in BindableBase will do that for me.

Next thing I need to do is I need to map corresponding View with the ViewModel. For that I am going to modify the MainPage.xaml as follows.
<storeapp:VisualStateAwarePage
    x:Class="PrismForWinRTDemo.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:prism="using:Microsoft.Practices.Prism.Mvvm"
    xmlns:storeapp="using:Microsoft.Practices.Prism.StoreApps"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PrismForWinRTDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        
    </Grid>
</storeapp:VisualStateAwarePage>

image
MainPage.xaml
I have included Microsoft.Practices.Prism.Mvvm namespace and set ViewModelLocator.AutoWireViewModel to True. So the Prism framework will map the view with the corresponding view model at the run time. 

Now I am going to add a StackPanel and create two text blocks to display FirstName and LastName. Those textbocks content will be bound to MainPageViewModels’ two properties.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
   <StackPanel>
       <TextBlock Text="{Binding }"></TextBlock>
       <TextBlock></TextBlock>
   </StackPanel>
</Grid>

image
No IntelliSense support for available properties
One of the advantages, Prism will give you is it will show the available properties to bind. But here as  you can see in the above image, FirstName is not displayed in the IntelliSense. The thing here is, in the design time my view has no idea about what it's ViewModel is. ViewModelLocator.AutoWireViewModel="True" will only work in the runtime. So for that let’s create a design time view model.

I am creating a folder named “DesignTime” and adding a class named MainPageViewModel which will only implement IMainPageViewModel. The reason for me to only implement IMainPageViewModel is since this is only for design time, I don’t have many functionalities like OnNavigatedTo,  INotifyPropertyChanged etc. So I don’t need to inherit from ViewModel. Here I will only have two properties in which in the constructor, I am setting some design time values to be displayed. The thing to note here is constructor will be executed in the design time as well.
namespace PrismForWinRTDemo.DesignTime
{
    public class MainPageViewModel : IMainPageViewModel
    {
        public string FirstName { get; set; }
 
        public string LastName { get; set; }
 
        public MainPageViewModel()
        {
            this.FirstName = "Design time first name";
            this.LastName = "Design time last name";
        }
    }
}
Next let’s modify the MainPage.xaml back again to show design time data.
<storeapp:VisualStateAwarePage
    x:Class="PrismForWinRTDemo.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:prism="using:Microsoft.Practices.Prism.Mvvm"
    xmlns:storeapp="using:Microsoft.Practices.Prism.StoreApps"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PrismForWinRTDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    prism:ViewModelLocator.AutoWireViewModel="True"
    xmlns:designtime="using:PrismForWinRTDemo.DesignTime"
    mc:Ignorable="d">
 
    <d:Page.DataContext>
        <designtime:MainPageViewModel />
    </d:Page.DataContext>
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <TextBlock Text="{Binding FirstName}" Style="{StaticResource HeaderTextBlockStyle}"></TextBlock>
            <TextBlock Text="{Binding LastName}" Style="{StaticResource SubheaderTextBlockStyle}"></TextBlock>
            <TextBlock></TextBlock>
        </StackPanel>
    </Grid>
</storeapp:VisualStateAwarePage>

image
MainPage.xaml
Here I have added the xml namespace for DesignTime and have set the design time view model under Page.DataContext. Since it is provided with “d:”, this will be removed in the runtime. Another thing is, as you can see in the below image, as I was typing, IntelliSense was suggesting me the available properties.

image
IntelliSense support for available properties
So the Design time data is working.

image
Design time
Now I am all set. Final things to do is navigate to “MainPage” in the App.xaml.cs. So in the OnLaunchApplicationAsync, I am going to navigate to the MainPage.

image
NavigationService.Navigate()
As in the above image, when I try to Navigate using the NavigationService provided by Prism, it is expecting a string. But in Windows Runtime, default behavior is, it is expecting a type of the page to be navigated. In Prism for Windows Runtime, there is this nice concept called Experiences. To give you a understanding about  experiences, let’s take the view “MainPage” and the view model “MainPageViewModel”. Here the default experience is “Main.”. (It’s same as the naming convention used in ASP.NET MVC. If we take the “HomeController”, the controller name is “Home.”). Of course the default experience naming convention can be changed according to your requirement. For now let’s adopt the default behavior.

So I am adding the Navigation experience as follows.
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
{
    this.NavigationService.Navigate("Main", null);
    return Task.FromResult<object>(null);
}

Since I don’t need any parameters to be passed, my second parameter is null.

Now I am all done. Let’s run the application.

image
Result
So that’s it. For more information on Prism for Windows Runtime visit,

I am uploading the full sample to my OneDrive.


Happy Coding.

Regards,
Jaliya