Introduction
I find the naming of the Model View ViewModel (MVVM) design pattern rather weird. To me, a name like for example, "ViewModel View Controller Model" would make more sense. After all, the novel idea with the MVVM pattern is the introduction of the viewmodel as the mediator between the view and the model, the choice of whether or not to use a controller is largely irrelevant to that design. However, the pattern has grown to be so popular that it is seen as the standard architecture for client-side Windows apps these days.
There are several reasons for the popularity of the MVVM design pattern but my favorite is the excellent separation of concerns between the view and the model. Databinding and the declarative nature of XAML inspires to creating reusable view components while the MVVM pattern offers an opportunity to offload application specific, non-reusable stuff to the viewmodel thus keeping the model and services reusable as well. Nice!
Having established that the viewmodel is the centerpiece of the MVVM pattern, it's not surprising that one of the first things to decide is when to instantiate it. There are essentially two ways to do this: view first or viewmodel first. Just as you would imagine, the name describes the order of creation; in a view first design the view is instantiated first, causing the viewmodel to be instantiated and connected to the view, while the opposite is the case for a viewmodel first MVVM design. The difference may seem rather academic but the choice will affect your design in very fundamental ways. For example, if you use the viewmodel first approach, you can use Data Templates to create the corresponding views "automatically" while supplying designtime data may pose more of a challenge compared to a view first approach.
Of course, there are advocates for both designs but I prefer the view first approach and in this article, I will explain how I usually hook up the viewmodel to the view these days. The idea is very simple so I'm sure it's being used in a lot of places even though I haven't seen it described yet. Hopefully, I can save some time for someone by sharing my thoughts.
Background
I have worked my way through a few methods to hook up the viewmodel to the view before arriving at the one described in this article. I'll list some of them here along with my reasons for preferring not to use them. All the examples below use the following, very simple, viewmodel.
public class ViewModel
{
public string Message { get; set; }
public ViewModel(string message)
{
Message = message;
}
public ViewModel()
{
Message = "Hello ViewModel default constructor!";
}
}
Code-behind
The most straight-forward way to connect the viewmodel (IMHO) is to simply set the DataContext
in the view constructor or in the handler of an event. Like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel("Hello MainWindow constructor!");
}
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
var textBlock = sender as TextBlock;
if(textBlock != null)
{
textBlock.DataContext = new ViewModel("Hello TextBlock Loaded!");
}
}
}
The major drawback with this approach is that you either have to create a new subclass for each view or handle an event to set the DataContext
. In a simple application, this might be okay but I prefer having a method that works equally well in a small application as in a large one. The following picture shows another big drawback with using events to set the DataContext
.
The top window is the designer in Visual Studio and the bottom window is the same application running. The difference shows that the Loaded
event does not fire in the designer and thus that setting the DataContext
in an event handler is unsuitable if you want the viewmodel to supply designtime data.
Instantiation in XAML
This might be the simplest way to instantiate a viewmodel, and it does support design data through the d: namespace
.
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
The major drawback with this approach is that you can only use the default, parameterless constructor for the viewmodel. In a non-trivial application, you'd most likely use a dependency injection (DI) container, like Unity for example, to resolve the viewmodel dependencies to services. When using a dependency injection container, I prefer to use constructor injection as opposed to property injection for the simple reason of easily being able to write unit tests for my viewmodels. If I use constructor injection, I don't have to bother with the DI container at all in my unit tests, instead I just create stubbed out versions of the services and use these as parameters to the viewmodel constructor in my test cases.
ViewModel Locator
Using a viewmodel locator is a very common way to handle the viewmodel instantiation in a view first MVVM application. The locator is simply an object that offers properties you can bind to retrieve a viewmodel. Here is a very simple implementation of a viewmodel locator.
public partial class Locator
{
public ViewModel ViewModel
{
get
{
return new ViewModel("Hello ViewModel Locator!");
}
}
}
The locator can be defined as a static resource in App.xaml.
<Application.Resources>
<ResourceDictionary>
<local:Locator x:Key="Locator"/>
</ResourceDictionary>
</Application.Resources>
And it's used like this to set the DataContext
.
<TextBlock DataContext="{Binding Source={StaticResource Locator}, Path=ViewModel}"
Text="{Binding Message}"/>
This design supports designtime
data and allows using constructor arguments but has the drawback of requiring adding a new property for each viewmodel added to the application. You can add new properties in partial classes so you don't have to change an existing file but I still don't like to have to change the locator for every added viewmodel. Another problem is that should the locator suddenly return a different type object than the view expects, it can go totally unnoticed until you realize your UI simply doesn't work anymore.
Using the clever design described here, you can totally avoid having to write new locator code for each added viewmodel. The trick is to use an indexer to choose which viewmodel to return from the one and only locator viewmodel property. This way of implementing the locator has a consequence that some find beneficial but I think is a weakness: The contract between the view and the viewmodel is very weak since the intex is just a string
. Typically you'd want loose coupling between the view and the viewmodel but having the coupling so loose you simply bind to a property as an act of faith is a bit too loose for me.
Markup Extension
I did use the markup extension described here for several projects and I was quite happy with it. However, this technique can't be used in Windows apps since custom markup extensions aren't supported in Windows Runtime XAML.
Using the Code
So, to summarize: I want a method to hook up a viewmodel to a view in a view first MVVM application with the following properties:
- Independent of other frameworks
- Declarative use in XAML
- Designtime data support
- Explicit contract between the view and the viewmodel
- No need to change existing code when adding new views/viewmodels
- Able to use constructor parameters to facilitate unit testing
- Compatible with WPF and WinRT applications
- Simple and light-weight yet able to expand into being more powerful when needed
The solution I came up with is this:
using System;
using System.Reflection;
#if !NETFX_CORE
using System.Windows;
#else
using Windows.UI.Xaml;
#endif
namespace WpfApplication4
{
public static class DataContext
{
#region Type ResolvedType
public static Type GetResolvedType(DependencyObject obj)
{
return (Type)obj.GetValue(ResolvedTypeProperty);
}
public static void SetResolvedType(DependencyObject obj, Type value)
{
obj.SetValue(ResolvedTypeProperty, value);
}
public static readonly DependencyProperty ResolvedTypeProperty =
DependencyProperty.RegisterAttached("ResolvedType", typeof(Type), typeof(DataContext),
new PropertyMetadata(null, OnResolvedTypeChanged));
private static void OnResolvedTypeChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
if(!_resourcesLoaded)
{
Assembly.GetExecutingAssembly().GetCustomAttributes(false);
_resourcesLoaded = true;
}
var elt = d as FrameworkElement;
if (elt != null)
{
elt.DataContext = CurrentResolver((Type)e.NewValue);
}
}
#endregion
public delegate object ResolverDelegate(Type type);
public static ResolverDelegate CurrentResolver = ActivatorResolver;
public static object ActivatorResolver(Type type)
{
return Activator.CreateInstance(type);
}
}
}
The code above implements an attached property called ResolvedType
holding a type. When the type held by the property is changed, the object where the attached property is set will have its DataContext
property set to an object resolved from the supplied type. The default behavior is to simply instantiate an object of the supplied type but it can be changed by applying a different ResolverDelegate
.
If you happened to notice the exotic code in OnResolvedTypeChanged
getting custom attributes, don't worry! I'm going to explain what it does and why it's needed below.
Here is the usage from XAML (in theory, you could also use the attached property from code-behind, but there's no point in doing that).
First WPF:
<TextBlock local:DataContext.ResolvedType="{x:Type local:ViewModel}" Text="{Binding Message}"/>
And then WinRT:
<TextBlock local:DataContext.ResolvedType="local:ViewModel" Text="{Binding Message}"/>
There seems to be an issue with the XAML parser on WinRT systems leading to the parser not recognizing the ResolvedType
value as a type in some cases. There is a way to work around the issue showing the XAML parser that an expression is indeed a type by defining a style for the type in question.
<Page.Resources>
<Style TargetType="local:ViewModel"/>
</Page.Resources>
This bug is unfortunate but I like the attached property approach enough to accept the workaround for now. I hope the issue will be corrected eventually (even though I won't hold my breath) and until it's fixed I'll just suck it up and apply the workaround when required.
Ok, so here we have a working example of setting the DataContext
using an attached property but in all honesty it's no better than instantiating the viewmodel directly in XAML because:
- There is a hard coupling between the view and the viewmodel (you need to supply the actual type if the viewmodel).
- A viewmodel default constructor is required.
- Viewmodel lifetime can't be controlled.
- Designtime data isn't supported. Actually, the viewmodel can detect being in the designer and supply designtime data in that case but I prefer using a separate viewmodel class for design to avoid cluttering my production viewmodels.
Luckily enough, all these shortcomings can be resolved by using a DI container. So let's start by adding a DI container to the solution. In the attached source, I'm using Unity Application Block (Unity) which can be added though NuGet.
Each DI container implementation uses a different syntax but they all provide the same basic service to look up a concrete implementation given a contract specification. Typically, there are several ways to set up a DI container: You can either use attributes in the source code, a configuration file or what's called a fluent interface to set up the relationship between contract and implementation. Attributes provide a nice way to decentralize the container setup but I prefer using the fluent interface because I don't want to spread container specific attributes all over my source code.
First, let's create the viewmodel contract:
public interface IViewModelContract
{
string Message { get; }
}
That's simple enough, the contract is just a string
property called Message
! Now let's create the production viewmodel
implementing this contract:
public interface IDummyService
{
}
public class DummyService : IDummyService
{
}
public class RunTimeViewModel : IViewModelContract
{
public string Message
{
get
{
return "Run-Time ViewModel";
}
}
private IDummyService _dummyService;
public RunTimeViewModel(IDummyService dummyService)
{
_dummyService = dummyService;
}
}
That's a bit more involved; in addition to implementing the required viewmodel contract, the RunTimeViewModel
also uses a service called DummyService
to which it obtains a reference through a constructor parameter. A good fit for constructor injection!
And here is the designtime counterpart.
public class DesignTimeViewModel : IViewModelContract
{
public string Message
{
get
{
return "Design-Time ViewModel";
}
}
}
Note that the designtime viewmodel doesn't use any services, it just provides the interface required by the viewmodel contract.
Now we must establish the relation between the contract and the viewmodel implementation to be able to resolve the viewmodel contracts. When using the fluent interface, this is typically done in a bootstrapper.
interface IUnityContainerInitializer
{
void InitializeContainer(UnityContainer container);
}
public class Bootstrapper
{
#region static bool IsInDesignMode
public static bool IsInDesignMode
{
get
{
#if DEBUG
#if NETFX_CORE
return Windows.ApplicationModel.DesignMode.DesignModeEnabled;
#else
return DesignerProperties.GetIsInDesignMode(new DependencyObject());
#endif
#else
return false;
#endif
}
}
#endregion
private static UnityContainer _container;
private static IUnityContainerInitializer _initializer;
static Bootstrapper()
{
if (IsInDesignMode)
{
_initializer = new DesigntimeContainerInitializer();
}
else
{
_initializer = new RuntimeContainerInitializer();
}
_container = new UnityContainer();
_initializer.InitializeContainer(_container);
DataContext.CurrentResolver = t =>
{
return _container.Resolve(t);
};
}
}
This is an example of a very simple bootstrapper. I deliberately stayed away from generalizing it to make the code easier to follow. The only thing that should really be put somewhere else is the IsInDesignMode
property but I chose to keep it in the bootstrapper to make the example as simple as possible. By the way, please notice that the IsInDesignMode
property always returns false
in release builds. Keeping dead code in production software destroys the warm-and-fuzzy feeling I usually get when I ship code.
As you can see, I have divided the bootstrapping sequence into three parts:
- A
DesigntimeContainerInitializer
or RuntimeContainerInitializer
is created based on the IsInDesignMode
property. - The
UnityContainer
is created and initialized. - The
CurrentResolver
delegate in the static DataContext
class is set to a lambda expression resolving the type by use of the container.
Now, we need to create the two different container initializers and here you can see the famed "fluent interface" in action, essentially it is the calls to RegisterType
below. It's called fluent because each function in the interface returns the container so function calls can be linked in a LINQ-like fashion, but it's really nothing fancy.
public class RuntimeContainerInitializer : IUnityContainerInitializer
{
public void InitializeContainer(UnityContainer container)
{
container.RegisterType<IViewModelContract, RunTimeViewModel>();
container.RegisterType<IDummyService, DummyService>();
}
}
public class DesigntimeContainerInitializer : IUnityContainerInitializer
{
public void InitializeContainer(UnityContainer container)
{
container.RegisterType<IViewModelContract, DesignTimeViewModel>();
}
}
As you can see, there are no services registered in the designtime container. The reason is simply that the designtime viewmodel doesn't use any in this example. However, in some cases, it makes sense to keep the viewmodel the same in designtime as in runtime but use special designtime services instead. That can be accomplished by registering the designtime services in the container in the same way as the viewmodels.
Ok, time for a recap.
I started out describing an attached property that can be used to set the DataContext
of a FrameworkElement
based on a Type
. Then followed a contract definition (interface) for a viewmodel and two different implementations of this contract: One for the final application (runtime) and one used to supply sample data in Blend or the Visual Studio designer (designtime). The next step was to create a bootstrapper setting up a DI container able to resolve the contract differently depending on whether it's loaded in the designer or not. Lastly, the CurrentResolver
delegate of the attached property was made to use the DI container to find the viewmodel implementation.
We are getting close but we're not quite there yet! In order to make this setup work, the bootstrapper constructor must be run, otherwise the DI container won't be initialized and the CurrentResolver
delegate won't be set. Since the application startup code isn't run by the designer, we have to use a different approach to instantiate the bootstrapper. I usually put it in App.xaml, like this:
<Application.Resources>
<ResourceDictionary>
<local:Bootstrapper x:Key="Bootstrapper"/>
</ResourceDictionary>
</Application.Resources>
Now maybe you would imagine that this is enough to be sure the bootstrapper is instantiated before the application is started (or before the designer starts executing) but since resources are loaded lazily, this is unfortunately not the case. To guarantee that the bootstrapper is loaded, we need something more explicit. First, let's define an assembly custom attribute.
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class LoadApplicationResourceAttribute : Attribute
{
public LoadApplicationResourceAttribute(string resourceKey)
{
Application.Current.TryFindResource(resourceKey);
}
}
This attribute tries to find a named resource in the current assembly using the supplied resource key when instantiated. This is actually enough to make sure the resource is loaded. I usually put this attribute in AssemblyInfo.cs but you can put it anywhere you like, for example in the bootstrapper class file.
The attribute is used like this:
[assembly: LoadApplicationResource("Bootstrapper")]
As you can see, the resourceKey
in this example matches the x:Key
value put on the bootstrapper in App.xaml above. This means that the bootstrapper will be loaded as soon as the attribute is instantiated. Which leads us to the next question: When is the attribute instantiated?
And the answer is: Custom attributes are instantiated when GetCustomAttributes
is called.
You might remember that I promised to explain the "exotic" code in OnResolvedTypeChanged
? Well, this is the code:
if(!_resourcesLoaded)
{
Assembly.GetExecutingAssembly().GetCustomAttributes(false);
_resourcesLoaded = true;
}
And I'm sure you get what it does and why it's needed by now. It is simply making sure all needed resources are loaded before resolving the first type. Now the circle is finally closed and the setup is complete!
Here is the result or our efforts, the attached application running to the left and in the designer to the right:
As always, I'm amazed at how many words are needed to convey a simple idea. I tried to keep the examples anaemic and to keep the explanations to a minimum but even then this turned out to be a quite long text. I'm not claiming that this is the best way to hook up a viewmodel but it is the way that suits me best right now. Tomorrow I might find all of this to be hopelessly outdated - one thing is certain: My view of that is the "best" way will change as I learn!
Hope you had a good time reading this and that you got some new ideas, even if you might not share my preferences when it comes to hooking up the viewmodel.
Points of Interest
The idea of using an attribute to load resources came from this article by Josh Smith. I generalized it to loading resources and made the addition with the call to GetCustomAttributes
in an attached property to get the same behavior in the designer as when the application is running. Later versions of Visual Studio do not instantiate custom attributes automatically anyway so you'll need some way to trigger that call even if you only want to use the mechanism for loading designtime data.
History
- 2015-06-22 - Initial version