January 28, 2012

WP7 Series Part 2: Ensuring Blendability with Dependency Injection

Starting with MVVM


In WP7 Series Part 1 I explained that I wanted to build a Windows Phone application using some basic MVVM principles to maintain 'Blendability'. After tinkering with some options, I've decided to use the MVVM Light Toolkit as the basic framework. It provides some good tools for the toolbox but doesn't otherwise drastically change how I code.

After installing the toolkit and creating a new MVVMLight phone application, open the App.xaml file and you'll find an entry in the Application.Resources section that looks like this:

<Application.Resources>
    <!--Global View Model Locator-->
    <ViewModel:ViewModelLocator x:Key="Locator" 
                                d:IsDataSource="True" />
</Application.Resources>

This 'ViewModelLocator' is the heart of the MVVM Light framework and is meant to be used by every page to find its data context. It does so by assigning a property of the Locator resource to the page's context, like so (at the top of MainPage.xaml):

DataContext="{Binding Main, Source={StaticResource Locator}}"

This line basically says "bind my DataContext to the 'Main' property of the 'Locator' resource". Everything so far is great, and pretty straightforward. A quick look inside the ViewModelLocator.cs file shows that the 'Main' property is a static instance of the MainViewModel.cs class. I'm not going to go into the details of how the ViewModelLocator instanciates the ViewModels, though, because I don't particularly like how it works. I'll show my variation a bit farther down.

Meanwhile, let's glance inside the MainViewModel.cs class. One of the first things I notice is the way DesignTime vs RunTime data is decided.

public MainViewModel()
{
    if (IsInDesignMode)
    {
        // Code runs in Blend --> create design time data.
    }
    else
    {
        // Code runs "for real"
    }
}

With this method, every ViewModel is going to have the same (or very similar) logic duplicated in its constructor. I'd rather have that logic centralized some place else, and have the ViewModel ignorant of its source of data (DesignTime or RunTime). It just uses whatever data it gets.

Enter Dependency Injection


Back to the ViewModelLocator. Since the ViewModelLocator is where the ViewModel classes get instanciated, it seems an appropriate place to decide where to get the data for the ViewModels. I understand that the MVVM Light Toolkit may eventually include a small Inversion of Control container (called SimpleIoc), but I'm comfortable with Ninject, so that's what I ended up using. It takes just a few seconds to install Ninject using NuGet.

In 'Blendable' apps, the concepts of design-time data and run-time data are equally important, so I decided to treat design-time data as an integral part of my data access layer. I like using the Repository pattern, even though its popularity may be waning in some circles, so it makes sense that I should have both design-time and run-time data repositories available.

After creating the repositories (as shown on the right, each implementing the IExampleRepository interface), I created Ninject modules for each of them. You'll notice I created a ViewModelModule; I use that in the ViewModelLocator also.

Now, returning to the ViewModelLocator, I can create a Ninject kernel, and add either the DesignTimeModule or the RunTimeModule depending on the same IsInDesignMode property that the MainViewModel was using. You can see that below in the BuildKernel() method.

My ViewModelLocator now looks like this:

public class ViewModelLocator
{
    private static StandardKernel _kernel;
 
    public ViewModelLocator()
    {
        BuildKernel();
    }
 
    public IMainViewModel Main
    {
        get { return _kernel.Get<IMainViewModel>(); }
    }
 
    private static void BuildKernel()
    {
        _kernel = new StandardKernel(new ViewModelModule());
 
        if (ViewModelBase.IsInDesignModeStatic)
        {
            _kernel.Load(new DesignTimeDataModule());
        }
        else
        {
            _kernel.Load(new RunTimeDataModule());
        }
    }
}

The final piece of the puzzle comes into place by changing the MainViewModel so that it's constructor asks for an IExampleRepository to be injected. The ViewModel itself doesn't care whether it's design-time data or run-time data.

The MainViewModel now looks like this:

public class MainViewModel : ViewModelBaseIMainViewModel
{
    private readonly IExampleRepository _repository;
 
    public MainViewModel(IExampleRepository repository)
    {
        _repository = repository;
    }
 
    public string ApplicationTitle
    {
        get { return "MVVM LIGHT"; }
    }
 
    public string PageName
    {
        get { return "My page:"; }
    }
 
    public string Welcome
    {
        get { return _repository.GetWelcomeMessage(); }
    }
}

The 'Welcome' message (displayed in the middle of the MainPage) is now retrieved through the injected repository, which may be either run-time or design-time data. The end result, in the emulator:


In Visual Studio, design view :



And, finally, in Expression Blend :


So there you have it: one way of injecting design-time and run-time data into a ViewModel using the ViewModelLocator and Dependency Injection, with just a few changes to the out-of-the-box MVVM Light template.

The code for this sample can be found at https://bitbucket.org/devadept/mvvmlightsample/

Read all posts in the WP7-Series


January 26, 2012

WP7 Series Part 1: To build a Windows Phone 7 app

And suddenly it's 2012... Where has the time gone? 

It's a new year, and I've decided to take on a new challenge by building a Windows Phone 7 app. I've had my Windows phone (an HTC HD7) for over a year, and I absolutely love it. I've not written a XAML app yet, nor a mobile app, but I saw mention of the 30 to Launch challenge a week or so ago, and have decided to give it a try.

I've done the File -> New Windows Phone Project a few times in the past year, but have never felt inspired enough to really delve into creating an app 'for realz', but one thing I do know: I don't want to use the standard out-of-the-box code-behind process. I really want to try to keep to an MVVM model and maintain good 'blendability'.

To that extent, I've tried to do a little research up front to look at some options. I could go the route that @kellabyte had taken during her learning experience and write much of the framework myself. Or, I could try to leverage as much as possible a framework somebody else has written, like Caliburn Micro or MVVM Light

I watched several of the training videos on Pluralsight, followed by all of the Full Stack series of videos, plus a few others like Laurent Bugnion's Deep Dive MVVM video on Channel 9. I've read through several tutorials, and browsed a bunch of open source code. I figure it's time to get off my butt and write some code.

So, after playing around with a few options, I've settled on a basic app structure that I'm happy with, that uses MVVM Light and Ninject at the core, along with a repository pattern wrapped around SQL CE for data. It allows for easy display of design-time-data in Blend, and adheres to MVVM very well. I'll explain more about the structure in my next post.