In my last post – Silverlight Navigation Part 3 – I outlined a mechanism whereby you could navigate to a View and have the application create and wire up the associated ViewModel automatically. I also showed the inverse of this, where you could navigate to a ViewModel and have the application automatically create and wire up the associated View automatically.
Whether you prefer the View-First or the ViewModel-First approach, the essential feature that really supports the ViewModel pattern is that the system should be able to create a ViewModel for a View (or vice versa) automatically. Otherwise, the burden falls to the developer to do this in code, which can result in a complicated architecture that’s either inflexible or difficult to understand and maintain.
Let’s say, for example, that you have adopted a View-First approach. Now, you could just have some code in your application (say, in a controller component or event handler somewhere) that simply creates the required View and it’s associated ViewModel and wires them together like this:
CustomerView view = new CustomerView();
CustomerViewModel viewModel = new CustomerViewModel();
view.DataContext = viewModel;
myContentControl.Content = view;
You can use this approach with a ViewModel-First approach too. Another simple approach is to just get the View to create its own ViewModel, either in its constructor:
public partial class CustomerView : UserControl
this.DataContext = new CustomerViewModel();
or via XAML:
All three of these approaches work great, except that they hard code your application to use specific View and ViewModel types. This may very well not be an issue for you, and if it isn’t, I say go for it!
However, there are times when you’ll want to have the View and the ViewModel types more loosely coupled. An example might be when you want to decide at run-time which View to display for a particular ViewModel based on, say, the user’s role, chosen UI theme, screen size, or even the type of device that the user is using(!). So, while the approaches above are simple, they are relatively inflexible.
It is at this point that the Dependency Injection folks will start to gesticulate wildly and remind us that this is exactly the situation in which DI excels. Remember that with DI, if you have a dependency between one class and another, the system (i.e. the DI container) can automatically fulfill that dependency dynamically at run-time for you. This allows the classes to be more loosely coupled and removes the need for you to manage the creation of dependent classes yourself. Let’s see how this works…
Say we have a class ‘A’ that depends on (i.e. has a reference to) a class ‘B’. Typical DI containers (including Unity) require that we express the dependency between A and B using a type – typically (but not necessarily) an intermediate interface type, say IB – and that we define a constructor on A that takes a reference to that type. We then register our implementation of the intermediate interface type with the container – so that it knows that whenever anybody wants an implementation of IB it will create an instance of B.
So, when we want an instance of class A, we just ask the container to create one for us. It spots that class A requires a reference to an IB implementation, so it goes and creates a B for us automatically and passes a reference to it to A’s constructor. The container manages the creation of dependent classes for us!
It is of course true that in many situations DI is a good solution for this kind of problem. I think though, that for the ViewModel scenario DI is not ideal. To illustrate why, let’s see how DI typically works in View-First and ViewModel-First scenarios…
In our View-First example above, we have a View that wants a reference to (depends on) a ViewModel, so we’d first register an implementation of our ViewModel with the container:
and we’d design the View so that it gets a reference to the ViewModel implementation in its constructor:
public CustomerView( ICustomerViewModel viewModel )
this.DataContex = viewModel;
Finally, we’d get the container to create an instance of the View. The container will automatically create an instance of the registered ViewModel type and pass a reference to it into the View’s constructor.
CustomerView view = _container.Resolve<CustomerView>();
Ok this works, but I think there are a number of problems with this approach:
So that’s Dependency Injection in a View-First world. What about a ViewModel-First world? Well, things are no better here either. Similar to the process outlined above, we’d probably define an IView interface; register an implementation of it with the container; define a constructor on the ViewModel that accepts an IView reference; then create an instance of the ViewModel using the container:
public CustomerViewModel( ICustomerView view )
((FrameworkElement)view).DataContext = this;
CustomerViewModel viewModel = _container.Resolve<CustomerViewModel>();
Again, a couple of problems with this approach:
In my last post on navigation, I showed a couple of different approaches to the problem of conjuring up a View for a ViewModel (or vice versa) without using a Dependency Injection approach.
Neither of these approaches are ideal though, so I got to thinking what an ideal approach might look like… The key is that we need a simple way of expressing the relationship between the View and the ViewModel types so that the system can just make the right things happen!
If you’re familiar with DataTemplates in WPF, you know that it’s possible to define a DataTemplate (somewhere in the application’s resources) for a particular (non UI) type. Whenever the system has to display an object of that type, the DataTemplate is automatically used to visually represent it. Under the covers, the system creates an instance of the DataTemplate, sets its DataContext to the object that it represents, and then displays it in the UI. Silverlight does not yet support implicit data templating – you have to specify the DataTemplate explicitly for each control – but the mechanism is very similar.
I think this is close to what we want…
I think of DataTemplates simply as “Thin Views” – i.e. purely declarative Views with no code behind. They are very useful, but sometimes you just need to have some code in the View (for complex visual behavior that can’t be done declaratively). So, if the system could be extended to include Views that could have code behind, it would all fit together in a nice, simple, consistent model. It could look something like this…
We define a View as usual and simply declare that it is associated with a ViewModel data type:
For the ViewModel-First approach, we simple create (or navigate to) an instance of the ViewModel and display it. For example,
MyContentControl.Content = new CustomerViewModel();
The system would then step in and create an instance of the View that corresponds to this type and would wire up the DataContext for us – just like the system does today with DataTemplates!!!
Similarly, for View-First, where we simply create (or navigate to) a View, the system would automatically create an instance of the associated ViewModel type for us and wire up the DataContext. There would likely be another property to control this behavior.
I think this approach has a number of benefits:
You’ll have noticed that we’re not using an intermediate interface type to loosely couple the View and ViewModel. The approach could be extended to support that though, for example by using the upcoming Managed Extensibility Framework (MEF), or by building in some form of simple Dependency Injection mechanism into the XAML loader system.
Until I prototype this approach more fully, it’s not clear whether it will really work as well as expected. Also, it’s not clear at this stage when (or if) we could expect it this approach to be implemented in the platform.
We can but dream though…