Adventures in MVVM – ViewModel Location and Creation
- by Brian Genisio's House Of Bilz
More Adventures in MVVM In this post, I am going to explore how I prefer to attach ViewModels to my Views. I have published the code to my ViewModelSupport project on CodePlex in case you'd like to see how it works along with some examples. Some History My approach to View-First ViewModel creation has evolved over time. I have constructed ViewModels in code-behind. I have instantiated ViewModels in the resources sectoin of the view. I have used Prism to resolve ViewModels via Dependency Injection. I have created attached properties that use Dependency Injection containers underneath. Of all these approaches, I continue to find issues either in composability, blendability or maintainability. Laurent Bugnion came up with a pretty good approach in MVVM Light Toolkit with his ViewModelLocator, but as John Papa points out, it has maintenance issues. John paired up with Glen Block to make the ViewModelLocator more generic by using MEF to compose ViewModels. It is a great approach, but I don’t like baking in specific resolution technologies into the ViewModelSupport project. I bring these people up, not to name drop, but to give them credit for the place I finally landed in my journey to resolve ViewModels. I have come up with my own version of the ViewModelLocator that is both generic and container agnostic. The solution is blendable, configurable and simple to use. Use any resolution mechanism you want: MEF, Unity, Ninject, Activator.Create, Lookup Tables, new, whatever. How to use the locator 1. Create a class to contain your resolution configuration: public class YourViewModelResolver: IViewModelResolver
{
private YourFavoriteContainer container = new YourFavoriteContainer();
public YourViewModelResolver()
{
// Configure your container
}
public object Resolve(string viewModelName)
{
return container.Resolve(viewModelName);
}
}
Examples of doing this are on CodePlex for MEF, Unity and Activator.CreateInstance.
2. Create your ViewModelLocator with your custom resolver in App.xaml:
<VMS:ViewModelLocator x:Key="ViewModelLocator">
<VMS:ViewModelLocator.Resolver>
<local:YourViewModelResolver />
</VMS:ViewModelLocator.Resolver>
</VMS:ViewModelLocator>
3. Hook up your data context whenever you want a ViewModel (WPF):
<Border DataContext="{Binding YourViewModelName, Source={StaticResource ViewModelLocator}}">
This example uses dynamic properties on the ViewModelLocator and passes the name to your resolver to figure out how to compose it.
4. What about Silverlight?
Good question. You can't bind to dynamic properties in Silverlight 4 (crossing my fingers for Silverlight 5), but you CAN use string indexing:
<Border DataContext="{Binding [YourViewModelName], Source={StaticResource ViewModelLocator}}">
But, as John Papa points out in his article, there is a silly bug in Silverlight 4 (as of this writing) that will call into the indexer 6 times when it binds. While this is little more than a nuisance when getting most properties, it can be much more of an issue when you are resolving ViewModels six times. If this gets in your way, the solution (as pointed out by John), is to use an IndexConverter (instantiated in App.xaml and also included in the project):
<Border DataContext="{Binding Source={StaticResource ViewModelLocator},
Converter={StaticResource IndexConverter}, ConverterParameter=YourViewModelName}">
It is a bit uglier than the WPF version (this method will also work in WPF if you prefer), but it is still not all that bad.
Conclusion
This approach works really well (I suppose I am a bit biased). It allows for composability from any mechanisim you choose. It is blendable (consider serving up different objects in Design Mode if you wish... or different constructors… whatever makes sense to you). It works in Cider. It is configurable. It is flexible. It is the best way I have found to manage View-First ViewModel hookups. Thanks to the guys mentioned in this article for getting me to something I love using. Enjoy.