Using Generic Types for MVVM

The MVVM pattern seems to have become the defacto standard for implementing cool WPF applications.

Rob Eisenberg suggested using Conventions to help enforce a separation of View and ViewModel. This to me smacks of Magic Strings which is just not nice.

Lately I’ve been playing with a different method of doing this using XAML Generics.

I’d like to share this with the community and see how you all feel about this approach.

The basic idea is that all Views should derive from a ViewBase where T specifies the type of ViewModel they should be built against.

For example:

Assume we have a ViewModel of type SomeViewModel and we want to create a view that represents it, all we have to do is create the following XAML:

<ve:ViewRoot x:Class="app.SomeView" x:TypeArguments="vm:SomeViewModel"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:ve="clr-namespace:ViewEngine;assembly=ViewFramework"
 >
</ve:ViewRoot>

and a Code Behind file:

public partial class SomeView : ViewRoot<SomeViewModel>
{
    public SomeView()
    {
        InitializeComponent();
    }
}

And bingo… our application will use SomeView everywhere SomeViewModel occurs in the visual tree.

Because of the data binding system we can now build our view referencing the view model, so assuming there is a Title property in the view model we can write this to a label like this:

<ve:ViewRoot x:Class="app.SomeView" x:TypeArguments="vm:SomeViewModel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ve="clr-namespace:ViewEngine;assembly=ViewFramework"
 >
      <Label Content="{Binding Title}"/>
</ve:ViewRoot>

No naming conventions, no DataTemplate writing, just completely transparent intent.

Framework Wire-Up

Of course this doesn’t happen out of the box and requires a framework and a little global wiring up.

Let’s start with the simple bit, wiring it up, and then get to explaining how this works behind the scenes.

To make it simple I did away with the App.xaml startup system and went back to the old static main in Program.cs approach… I have no doubt it could be integrated into the app.xaml system if needed.

[STAThread]
public static void Main()
{
    var app = new Application();
    ViewEngine.Initialise(app, Assembly.GetExecutingAssembly());
    ViewEngine.Run(new WindowViewModel());
}

Simple huh?

Framework

Of course all the magic and challenge happens in the framework itself.

The basic principle is straightforward:

  • Scan the provided assembly and find all subclasses of ViewRoot.
  • Set up mappings between the ViewClasses and their models.
  • Wrap those in DataTemplates.
  • Load the data templates into the applications root ResourceDictionary.

The rest is handled by WPF for us.

There are however a couple of challenges to using Generics in WPF that make this more complex than one might expect.

Access to Properties

Not being able to access things like ResourceDictionary properties on the children of a generic type.

Fix: Create a 2 stage derivation of ViewRoot, the first called ViewRoot and the second called ViewRoot. This allows us to use the convention in the XAML and keeps the established XAML conventions runnings.

    public class RootView<T> : RootView { }
    public class RootView : ContentControl { }

Top Level Windows

Of course top level windows cannot be derived from ContentControl and must be derived from Window so we have to introduce some special case handling.

Its own assembly

As I discovered in one of my earlier posts on XAML it is important to build the ViewEngine in a separate assembly.

View Engine

Still it’s pretty plain sailing, in fact a whole ViewEngine class can be presented here. Obviously this isn’t commercial ready but it gives you a base to play with.

public interface IView { }
internal interface IViewRoot : IView { }
public class ViewRoot<T> : ViewRoot { }
public abstract class ViewRoot : ContentControlIViewRoot { }
public class WindowRoot<T> : WindowRoot { }
public abstract class WindowRoot : WindowIView { }


public static class ViewEngine
{
    private static Application sApp;

    public static void Initialise(Application app, params Assembly[] assembliesWithViews)
    {
        sApp = app;
        CreateViewViewModelMapping(assembliesWithViews);
    }

    public static Window Run(object viewModel)
    {
        var rootWindow = CreateRootWindow(viewModel);
        sApp.Run(rootWindow);
        return rootWindow;
    }

    private static void CreateViewViewModelMapping(IEnumerable<Assembly> assembliesWithViews)
    {
        foreach (var assemblyWithViews in assembliesWithViews)
            AddViewTypesToTemplates(assemblyWithViews.GetTypes());
    }

    private static void AddViewTypesToTemplates(IEnumerable<Type> potentialViewTypes)
    {
        foreach (var potentialViewType in potentialViewTypes)
            if (TypeImplementsValidViewInterface(potentialViewType))
                AddViewTypeMapping(potentialViewType);
    }

    private static bool TypeImplementsValidViewInterface(Type potentialViewType)
    {
        if (typeof(IView).IsAssignableFrom(potentialViewType))
            return potentialViewType.BaseType.GetGenericArguments().Length > 0;

        return false;
    }

    private static void AddViewTypeMapping(Type viewType)
    {
        var modelType = viewType.BaseType.GetGenericArguments()[0];

        if (typeof(IViewRoot).IsAssignableFrom(viewType))
        {
            var template = new DataTemplate(modelType);
            var visualFactory = new FrameworkElementFactory(viewType);
            template.VisualTree = visualFactory;

            sApp.Resources.Add(template.DataTemplateKey, template);
        }
        else
            sApp.Resources.Add(modelType, viewType);
    }

    private static Type FindViewForModelType(Type modelType)
    {
        return sApp.Resources[modelType] as Type;
    }

    private static Window CreateRootWindow(object viewModel)
    {
        Type viewType = FindViewForModelType(viewModel.GetType());
        if (viewType == null)
            throw new Exception(string.Format("No View for ViewModel type: {0}",
                         viewModel.GetType().Name));

        var view = Activator.CreateInstance(viewType);
        var window = view as Window;

        if (window == null)
            throw new Exception(string.Format("Could not initialise root WindowView({0})",
             viewModel.GetType().Name));
        window.DataContext = viewModel;

        return window;
    }
}

In case you also need an example MainWindow it is straightforward:

<ve:WindowRoot x:Class="app.MainWindow" x:TypeArguments="WindowViewModel" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ve="clr-namespace:ViewEngine;assembly= ViewEngine " 
        Title="{Binding TitleProperty}" Height="300" Width="300"
        Content="{Binding ContentProperty}"
 >
    <ve:WindowRoot.Resources>
    </ve:WindowRoot.Resources>
</ve:WindowRoot>

Have fun and do let me know if you find any way to make this better…

see also

You must be logged in to post a comment.

community content (1 approved comment so far)
Click to expand

Sharply Handling Errors
Click to expand

As we all know C# provides for relatively elegant handling of errors with its try{} catch{} finally {} construct.

There are a couple of gotchas such as ThreadExceptions which bypass this stack and can only be caught at application level but for the most part it works ok.

However, there is one bug bear that drives me nuts, nuts enough that I have to write about it.

Catching multiple exception types

To catch multiple types of exception coming out of a block of code we are forced to write multiple catch() blocks, one for each type of exception.

If it makes sense from an application perspective to treat these differently then no problem, however, if we want to catch a lot of different exception types and perform some relatively simple logic on them (such as logging and re-throwing) it can be really irritating (not to mention buggy and hard to read) to maintain a long list of blocks.

Sure, we can factor out our exception handling into its own method, but this breaks the readability of the code and still requires a long list of “catch(…) {HandleError();}” statements which is a pain.

Wouldn’t it be nice if instead we could use syntax more like the using statement?

catch(ArgumentException)
catch(OutOfMemoryException)
catch(UnathorisedAccessException)
catch(CustomException)
{
    // handle error here
}

Now I realise that this has a problem, kind of a big one – what about the error object?

Well, that brings me first to another point… why do we always have to name our error object ex?

catch(Exception ex){}

Since we can only ever have a single error object inside a given catch block couldn’t we do something more like the set{} accessors? I.e. automatically name the object “value”?

e.g.

catch(ArgumentException)
{
    var msg = value.Message;
    // handle error here
}

Well, yes and no. I mean it looks nice and I have no doubt it would function… but unfortunately we can nest try-catch blocks within each other… so we would get name clashes (which instance of “value” are we talking about…).

Should we ever nest try-catch blocks within a catch block? I can’t say I ever have… I would argue that if error handling gets that complex it should be moved out to its own method. Unfortunately someone somewhere has probably done this so introducing this automated error handling would be a breaking change 🙁

Assuming such a change was possible then we could handle the multiple exception types realtively nicely by simply having the type of ‘value’ be the base type Exception. Why is this valid? Because by catching multiple exception types in a single handler we have already declared that we do not have any interest in their specific contents… so being able to get the basic data should be more than enough.

catch(ArgumentException)
catch(OutOfMemoryException)
catch(UnathorisedAccessException)
catch(CustomException)
{
    log(value.Message);
    Application.Exit();
}

Sadly this is all a pipe dream, but I’d love to hear your thoughts on it… especially if you are a frequent user of nested catch blocks.

Update

I thought about this some more and came up with another syntax which might work and which perhaps could be done without making it a breaking change:

catch(ArgumentException,
     OutOfMemoryException,
     UnathorisedAccessException,
     CustomException) as ex
{
    log(ex.Message);
    Application.Exit();
}

Since we currently can’t use commas in the catch() part by introducing a comma we notate instantly that we are using the new syntax, we can list as many types as needed with minimal effort, and we can re-use (read abuse) the ‘as’ keyword to name the resulting object.

In this way we can have everything we want without breaking existing code… always a bonus 🙂

Connect

Turns out I’m not the only user with this desire… I found this Microsoft Connect sugestion on the same topic 🙂

see also

You must be logged in to post a comment.

community content (no approved comments so far)
Click to expand

Most basic XAML
Click to expand

As part of gaining a deeper understanding of WPF I felt it was important to gain a deeper understanding of how XAML works and what it actually means. Therefore I will attempt to use XAML independantly of WPF…

Naturally my first question was “What is the simplest XAML file I can conceive of?”.

What I came up with was this:

<sys:Object xmlns:sys="clr-namespace:System;assembly=mscorlib">
</sys:Object>

If you create a new Console Application and add a code file called “Test.xaml” then enter the above code it will build. Yipee.

But what does it mean?

I was assuming it creates a new type extending Object, unfortunately since I couldn’t specify a type name I had no way to test that assumption. So from here I wanted to extend my question to include “and I can reflect on”.

A bit more playing landed me this:

<sys:Object x:Class="TestType"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</sys:Object>

This allows me to create a new type called TestType that extends Object. How do I know this? I can access it from my Main function by calling:

TestType t = new TestType();

Great… so I fire up reflector expecting to find a decompilation giving me:

using System;

namespace ConsoleApplication1
{
    public class TestType : Object
    {
    }
}

But, no, it is a load more complex than that. What I actually get to see is:

[GeneratedCode("PresentationBuildTasks", "4.0.0.0")]
public class TestType : IComponentConnector
{
    // Fields
    private bool _contentLoaded;

    // Methods
    [DebuggerNonUserCode]
    public void InitializeComponent()
    {
        if (!this._contentLoaded)
        {
            this._contentLoaded = true;
            Uri resourceLocator = new Uri("/ConsoleApplication1;component/basictest.xaml",
 UriKind.Relative);
            Application.LoadComponent(this, resourceLocator);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never), DebuggerNonUserCode]
    void IComponentConnector.Connect(int connectionId, object target)
    {
        this._contentLoaded = true;
    }
}

Holy batman and robin. That was not quite what I expected, although the good news is it does indeed create a new type that derives from Object it also implements IComponentConnector.

However, when you stop and think a little it appears that XAML is in fact the conflation of 2 quite different concepts. The first is class definition (what we expected) and the second is Property Assignment (the extra stuff).

I’m assuming therefore that calling InitializeComponent will traverse through the inner XAML setting all the properties of the object.

Unfortunately using Object as the root does not let me test this, so I quickly whip up a simple base class:

using System;

namespace ConsoleApplication1
{
    public class SimpleBase
    {
        public string PropertyOne { get; set; }
        public string PropertyTwo { get; set; }
    }
}

And then modify my XAML to:

<custom:SimpleBase x:Class="TestType"
                    xmlns:custom="clr-namespace:ConsoleApplication1;assembly="
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</custom:SimpleBase>

NOTE: Notice the use of “;assembly=” at the end of the namespace definition, this is the most conformant way of specifying “look in the current assembly”. It also has the added advantage of making it easy to re-direct later if you refactor the type into a new assembly.

OK, so with that done I can again compile my program and I expect it to be just creating a new instance of TestType (derived from SimpleBase) but not yet setting any properties.

Score one for careful thinking… it does exactly that.

Next up I add a call to on my object t.

TestType t = new TestType();
t.InitialiseComponent();

I would expect this to change nothing since I don’t actually specify any of the properties in XAML.

And indeed it doesn’t, however it does change the hidden field “_contentLoaded” to true.

So for the next test the obvious step is to specify some values for the properties and see if they get set a] before the call to InitialiseComponent or b] after (or c] never…).

<custom:SimpleBase x:Class="TestType"
                    xmlns:custom="clr-namespace:ConsoleApplication1;assembly="
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            PropertyOne="Hello"
            PropertyTwo="World"
>
</custom:SimpleBase>

I can tell you now that the expected happens and the values are set after the call to initialise component.

So the first step of understanding XAML is completed.

What is XAML?
It is a conflation of Type Derivation and Property Setting.

Urg, I hate conflations. But OK, it is what it is and that is the future of programming according to MS.

Join me next time to dig deeper into XAML and how to use it.

see also

You must be logged in to post a comment.

community content (no approved comments so far)
Click to expand
Design and Content © Copyright Duncan Kimpton 2010