View Model Loading by Convention

Following up on my previous post on how you can achieve no code-behind for your WPF or Silverlight application, I will explain one possible way of doing view model instantiation using any Inversion of Control container and using a naming convention to do it automatically.

MVVM Project Structure

InTheBoks_structureOne of the first things you learn when searching for training material on MVVM in the context of Silverlight and WPF, is that many developers tends to chunk all their View Models and Views into a single project folder. This might work for a small project that has a minimal set of views, but for any bigger projects this will quickly become a mess so my advice is to avoid it altogether, you never know if your project will expand beyond your initial plans.

Either create a root-folder for all of your functional areas, or create a root-folder that contains all your features. I like to use the convention of a folder named simple “Features”. Within this folder, I create another folder for each distinct functional area of my app. Each functional feature can easily contain one or multiple views and view models.

On the right you can see an screenshot of the current structure for my InTheBoks project, where the ViewBase.cs from my previous blog post is stored under a Framework section.

With this structure, your View (e.g. MainView.xaml) and your View Model (e.g. MainViewModel.cs) will end up under the same .NET namespace, which is important when we want to load the view model by-convention.

What does by-convention mean? It’s simply figuring out the full type-name for the view model by following a defined project structure where we no longer need to manually connect the view and the view model.

Expanding the ViewBase

It’s time to expand the ViewBase we first defined in my previous post on No Code-Behind for MVVM. Inside the constructor of my PageView, UserControlView, WindowView (WPF) and ChildWindowView (SL), I set the DataContext with a call to an ViewBaseHelper class. This is done right after the InitializeComponent has been called using reflection.

DataContext = ViewBaseHelper.Instance.LoadViewModel(GetType());

The full source for my ViewBaseHelper is of course included in the sample download at the bottom, but here is the essential part that tries to load your View Model automagically:

internal object LoadViewModel(Type viewType)
{
    if (viewType == null)
    {
        return null;
    }

    var viewModelTypeName = viewType.AssemblyQualifiedName.Replace(viewType.FullName, viewType.FullName + "Model");

    var viewModelType = Type.GetType(viewModelTypeName);

    if (viewModelType == null)
    {
        return null;
    }

    return Container.Resolve(viewModelType);
}

In my example code I have relied upon Autofac as my choice for Inversion of Control container. The code that handles dependency injection is fairly small and can easily be replaced with an alternative IoC container.

What about design-time?

The method I’ve explained for convention based view model loading doesn’t work for design-time, which fortunately we have a solution for.

While this method does break somewhat with the idea of not directly binding the view to any view model type, this is only for design time and it can be very useful as you have a finer degree of control on which type you bind your view against and how you want it to be initialized.

All you need to do is add an d: element (which is ignore during compilation) which specifies the view model type and whether you want to create an actual instance of the VM or not. Here is an example from my MainView. First you need to import the namespace on which the view model is located and then set the d:DataContext attribute. IsDesignTimeCreatable is used to indicate if you want an object instance of the VM type.

xmlns:Feature="clr-namespace:InTheBoks.Features.Main"
d:DataContext="{d:DesignInstance Type=Feature:MainViewModel, IsDesignTimeCreatable=True}"

asd

Create new Feature

One of the additional things I’ve done for InTheBoks, is to create templates for new features which creates the view and the view model with proper inheritance, namespace imports, and design-time binding. To do this yourself, simply add the correct .zip file with your template items in the following folder:

\Visual Studio 2010\Templates\ItemTemplates\Silverlight

I won’t go into further detail on this today, though this is a good thing to do if you’re working on a big project that has many views. This is how it can look when you customize your items with icons and illustrations.

InTheBoks_feature

Download the Source Code

While my previous example was built around WPF, this new one is built using Silverlight. As this concept and code is built around InTheBoks, the name of the sample and the namespace is “InTheBoks”.

The sample doesn’t include any advanced MVVM-technologies such as commanding, only the one that is built into Silverlight 4 which is binding. For the purpose of clarity, I removed any other external dependency than Autofac.

Here is the download: InTheBoks-2010-06-20.zip.


Comments

Comments are closed

Pages

Search

Tags

None

    Recent posts

    Recent comments

    Blogroll

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.