Using conventions and StructureMap to wire up Views and View Models

In the small WPF project I’m currently working on we are using MVVM (Model - View - ViewModel) to separate our UI concerns from other logic.

Now for various reasons we’ve ended up with two main projects (excluding tests): the core application DLL, and the WPF UI executable that references the core DLL. Our ViewModels are defined in the application DLL, which knows absolutely nothing about the UI executable. Our Views (XAML) live in the UI exe, and depend on the ViewModels in the core DLL. All pretty standard.

The one hiccup is that sometimes our application DLL needs to do something that will result in getting a reference to a view. For example, an application controller, screen conductor, or in our case, an ApplicationShellViewModel needs to load up the relevant views (it’s a small project, remember? :)). So how does it do this when it knows nothing about the views in the UI exe?

In this case we decided to use a convention to map a ViewModel to a View. We’ve mandated that each View will have one and only one ViewModel (not strictly always the case, but works for us). So we can use our ViewModel types as “currency” to deal with our views, and exchange it for a view when required. We just need a way to map between a ViewModel and its View.

The way we decided to do this mapping is to use an IView marker interface (defined in the core DLL) on all our views in the UI exe, and use a ViewFactory class to resolve an IView based on the name of a ViewModel, with the help of our IoC container (StructureMap 2.6). The naming convention we’ll use is very simple: if we have a GherkinViewModel, we expect the matching view to be of type Gherkin. If you’re new to IoC containers this all probably sounds a little confusing, so let’s look at some code.

Note: This is probably a good time to stress that this post isn’t about great ways to wire up MVVM components. It is more an example of using conventions and StructureMap to implement a fairly naive approach to View/View Model wire-up. If you are after more the former than the latter then you may want jump over to Nikhil’s post on View/ViewModel association. I won’t take it personally. :)

The ViewFactory

Given a ViewModel type, we want our ViewFactory to get an instance of the IView for that view model using our naming convention. Let’s write a test for this, specifying that we want to resolve an IView named “Example” for our ExampleViewModel:

public class ViewFactoryFixture {
    [Test]
    public void ShouldResolveViewForViewModelUsingNamingConvention() {
        var exampleView = MockRepository.GenerateStub<IView>();
        var applicationFactory = MockRepository.GenerateStub<IApplicationFactory>();
        var viewFactory = new ViewFactory(applicationFactory);
        applicationFactory.Stub(x => x.ResolveNamed<IView>("Example")).Return(exampleView);

        var result = viewFactory.CreateViewFor<ExampleViewModel>();

        Assert.That(result, Is.SameAs(exampleView));
    }

    public class ExampleViewModel {}
}

The ViewFactory will need to use our IoC container to resolve the instance, which we’ve wrapped in an IApplicationFactory interface (not the best name perhaps – it creates application objects). Our test is specifying that when we ask the ViewFactory to create a view for our ExampleViewModel type, it should return the instance resolved from the IApplicationFactory named “Example”. Let’s pass this:

public class ViewFactory : IViewFactory {
    private IApplicationFactory _applicationFactory;

    public ViewFactory(IApplicationFactory applicationFactory) { _applicationFactory = applicationFactory; }

    public IView CreateViewFor<TViewModel>() {
        var viewNameByConvention = typeof (TViewModel).Name.Replace("ViewModel", "");
        return _applicationFactory.ResolveNamed<IView>(viewNameByConvention);
    }
}

Now we just need to implement an IApplicationFactory class and we’re done.

Registering named views in StructureMap

For our project our core StructureMap configuration lives in the core application DLL – the one with no references to the UI exe that has our views. Thankfully StructureMap has a really nice way of looking through assemblies and wiring up types you’re interested in.

class CoreRegistry : Registry {
    public CoreRegistry(IApplicationFactory applicationFactory) {
        For<IApplicationFactory>().Use(applicationFactory);
        Scan(x =>
            {
                x.AssembliesFromApplicationBaseDirectory(
                    assembly => assembly.FullName.StartsWith("DaveSquared."));
                x.AddAllTypesOf<IView>().NameBy(type => type.Name);
                x.WithDefaultConventions();
            });
    }
}

Registry is a StructureMap type that is used to configure the container. We’re telling StructureMap to scan the assemblies in the application base directory, and add those that are specific to this project (which in this example will be DaveSquared.MvvmConventionWireup.Core and DaveSquared.MvvmConventionWireup.UI). The magic happens in this line:

x.AddAllTypesOf<IView>().NameBy(type => type.Name);

Here we’re telling the StructureMap scanner to add all types that implement IView into the container, and name each specific type by the short type name. This, you’ll remember, is our naming convention. When asked for the view for ExampleViewModel we’ll lookup an IView called “Example” (which will live in the UI project in a Example.xaml file).

Some other quick notes: WithDefaultConventions() tells StructureMap to automatically wireup cases where there is only one concrete type that implements an interface (for example, Foo for IFoo). Also we register a singleton IApplicationFactory instance, as we need this as a dependency into our ViewFactory.

The last step is just to put this altogether for our IApplicationFactory implementation:

public class ApplicationFactory : IApplicationFactory {
    public ApplicationFactory() {
        ObjectFactory.Initialize(x => x.AddRegistry(new CoreRegistry(this)));
    }

    public T Resolve<T>() {
        return ObjectFactory.GetInstance<T>();
    }

    public T ResolveNamed<T>(string name) {
        return ObjectFactory.GetNamedInstance<T>(name);
    }

    class CoreRegistry : Registry { /* ... snipped, already shown above ... */ }
}
Aside: I can’t help but point out that this ApplicationFactory is covered by tests. We make sure we can resolve views by name, and resolve a view factory, and a few other key instances. These are integration tests, but I’ve made the mistake of not testing this stuff before and having it grow into a real mess, the lack of tests encouraging sloppiness to creep in. There are better ways to test more complex configurations, but this is a nice and simple approach for a nice and simple app.

We can now resolve Views like this from within our core application DLL code:

public ApplicationShellViewModel(IViewFactory viewFactory) {
    Top = viewFactory.CreateViewFor<FunkyViewModel>();
    Bottom = viewFactory.CreateViewFor<AwesomeViewModel>();
}
public IView Top { get; set; }
public IView Bottom{ get; set; }
Note: Check out Prism / Composite WPF or Caliburn for real ways to do view composition. :)

Final thoughts

This post has shown a basic example of how to use conventions to resolve Views from ViewModels in situations where you don’t want to have hard references to View types. I have no idea if this is a blatant misuse of StructureMap or IoC containers in general (please correct me! :)), but it is working fine for us at the moment. It is especially nice to just name a View and have it auto-magically wireup to its ViewModel. It’s not quite as nice for the poor designer, but in our case we’re only doing fairly basic UI for which I’ve found it easier to deal directly with the XAML.

One thing to keep in mind is that our ViewFactory and ApplicationFactory classes reference our container, which means we want to be very careful how widespread their use becomes in the application. Ideally you only want a couple of references to your IoC container in your application, so for us we only have it referenced in the class that handles our startup, and in our application shell (which is playing the role that an application controller or screen conductor might play in a larger app).

Hope this gives you some idea of how easy it is to get some simple conventions going in your code. If I’ve glossed over anything you’d like to know more about feel free to drop me a line.

Comments