Why?
I've created this post because I really love WPF and MVVM, but I hate ViewModelsLocator or however it is called. Generally I'm talking about this totally ugly static class that can be called God-Class, where we have all view model instances resolved. It is probably the most lazy solution and the most often used. Of course I'm not talking about an enterprise solutions like Prism, where everything is done and you don't need to create an ugly locator because you have ViewModelLocationProvider where you can define that you want to use DI (e.g. Unity). I'm rather targeting simple frameworks helping working with MVVM, like MVVM Light, Simple MVVM...and more.I decided to make a different solution, clean enough to forget about adding view model locator getters every time I'm adding new screen or new ViewModel. What is also important I didn't want to add too much boilerplate code.
First of all, why we need something like a ViewModelLocator? When we use DI with IoC we will face a problem with injecting some services to ViewModels. And here problems come, because how to tell WPF that we want to inject services to constructor before instantiating it and putting as a DataContext for our View?
The Code
I just show you the code and then try to explain it a little bit. Look below.
Then we can just call a public method ViewModelResolver.ConfigureViewModels(...).
How it works
As you can see, I'm using Unity DI to resolve ViewModel instance: public void ConfigureViewModels(IUnityContainer container) {...}, but it can be any injector of course, you will just need to slightly change this method to register ViewModels regarding container convention that you are using.Let me just describe it shortly, to clarify what we've got here.
Runtime template maching
The most important method here is not the first one, but the one that is dynamically creating DataTemplate for ViewModel and registers it in our resources. I called it CreateTemplate, yep brilliant, I know :-) Lets look closer on it.So, if you used to use "standard" way of matching DataTemplate to ViewModel, you are probably familiar with a solution like this one:
And put all such definitions in one of you Resource Dictionaries XAML file. And now the method CreateTemplate is doing it automatically in runtime, so, no need to worry about forgotten Data Template somewhere in XAML. Very useful here was a class ParserContext. It is the class that can create and describe the whole context of XAML file. Here I'm building xmlns namespaces for XAML elements, that I'm adding further. This method is just building all required namespaces, then creates relations between all prefixes and namespaces to finally dynamically parse my XAML code in runtime. Of course parser is universal so it returns object, I know that my object is DataTemplate, so I can freely cast it. Why am I doing this using parser not other tools? Answer is simple, no chance to create DataTemplate dynamically that will contain such code inside. You can't create it using plan C# without XAML code...unfortunately.
The second most important part is adding created DataTemplate instance to resources, this is much simpler, no parsers are required :-)
Simple code nothing to explain. Other methods are just helpers, and a result of refactoring, for matching only interfaces or view models.
There is one very important assumption in my code, you will need to follow MVVM naming convention, so xxxViewModel.cs, xxxView.xaml, xxxView.xaml.cs and each ViewModel must have a corresponding interface as a marker for DI / IoC container, IxxxViewModel.cs.
Hope the post helps! Feel free to comment. Thanks.
Comments
Post a Comment