Leveraging MEFedMVVM ExportViewModel – MEFedMVVM Part 2
In this post I will explain and show case what you can do with your VieModel by leveraging MEFedMVVM. If you want an introduction to MEFedMVVM please go here.
In order to make your ViewModel discoverable you simple decorate the ViewModel with ExportViewModel and give your view model a name so that the View can import the ViewModel by name. Some thing like this
and the view can look for this view model like this
The ViewModelLocator.ViewModel will leverage MEF to go get the exported ViewModel and set an instance of that ViewModel as the UserControl’s DataContext. BUT there is more stuff you can do.
The best way how to have design time data is by having Data Services injected in the ViewModel so that at design time you inject design time services and at runtime you inject the real services. This also allows you to better unit test because you can mock the data services while unit testing.
MEFedMVVM allows you to easily export services so that you can then import these services in the ViewModel. When you are exporting the service you also supply MetaData which is used by MEFedMVVM to decide which service to inject. Let’s do a quick example. Let’s say your ViewModel is using a service that implements IUserService to get a list of user from a database at runtime and you create another implementation of this service for design time that just returns a static list of Users. you would export these services like this
Design time Service
As you can see all you do is decorate the service with the Export Service attribute and specify if its Runtime or DesignTime. You can also specify ServiceType.Both if you want that service to be injected both at runtime and design time. I will talk more on the Export Service and what you can do with it in my next post. Just to give you a quick insight of what this can do here is a small list
- Have shared services (a service that is shared for all ViewModels)
- Have prioritized Services (have a service priority and MEFedMVVM will pick the appropriate service to be injected)
- Have IContextAware services. These are special UI related services. Basically MEFedMVVM will call InjectContext passing the UI element that requested the ViewModel, so that service can work as a bridge for the ViewModel and the View without any coupling. (This is one of my favorite features)
OK let’s not get side tracked. Were are we?
We have a ViewModel that is an empty class decorated with ExportViewModel and we have two services exported one for runtime and one for design time.
In order to inject the services we need in our ViewModel, we need to state that in the ExportViewModel attribute, like this
This will tell MEFedMVVM to get that service and inject it to the ViewModel. But how can MEFedMVVM inject this in the ViewModel? Well in order to do so your ViewModel must implement an interface called IServiceConsumer. Here is the interface contract.
So you will have a ServiceLocator property from where you can get the Services injected from and you need a method called OnServicesInjected which will be called when MEFedMVVM injects the services.
Don’t worry if you do not want to implement the interface yourself we made the heavy lifting for you. You can inherit from BaseViewModel which implements this interface for you. BaseViewModel also implements the INotifyPropertyChanged so you can do PropertyChanged notifications by calling OnPropertyChanged( () => Myproperty); Yes the implementation of INotifyPropertyChanged we used leverages lambdas so that you do not have spelling mistakes when doing property changed notifications
Back to service injection…. So our ViewModel is not implementing IServiceConsumer or inheriting BaseViewModel; inside the OnServicesInjected you can get the services and get the data you need. Like this
So here I am getting the data from the IUsersService that was injected and adding them in a collection which is bound in the View.
So yea finally my designer can see this in Blend
This sounded like a lot of work because I went into details of how everything works. But try it and you’ll see how easy it is to do. If its not easy enough get back to me and I really want to hear your feedback.
What if I do not have a service injected but I still want design time data??
Yes, I agree. There are some ViewModels that do not have a service injected BUT they still want design time data. An example of this… Let’s say you have another ViewModel which renders the SelectedUser which the end user selects from the other ViewModel. This ViewModel does not have a service because the data is coming from either from a Mediator callback or from a Property that is bound to some UI…. How can I have Design time data for this ViewModel?
MEFedMVVM let’s you do this as well. All you need to do is implement the IDesignTimeAware. This is the interface
The DesignTimeInitialization method will be called on your ViewModel (ONLY AT DESIGN TIME) and inside there you can do what you want in order to have Design Time Data. Here is an example
This will render like this in Blend
What if the DataContext is set because I am in a DataTemplate? How can I get Services injected and some design time data as well?
Very well. Sometimes we have scenarios when you have a DataTemplate that has a UserControl inside. This UserControl will still have a ViewModel set as its DataContext but it must not be set from MEFedMVVM ViewModelLocator.ViewModel attached property since the ContentControl or the ItemsControl should be setting the DataContext.
You can still do this with MEFedMVVM! In the ExportService you can have an additional parameter stating that this ViewModel should be “DataContextAware”. Something like this
The second parameter passed set to true is where you specify that this ViewModel needs to be “DataContextAware”.
What is this gonna do?
Well at Runtime it will not create an instance of the ViewModel, instead it will wait until the DataContext is set on the UIElement. When DataContext is set, it will inject the services that you requested in the ExportViewModel.
At DesignTime it will create the ViewModel instance and inject it in the DataContext of the UI element so that you can still design your UI seamlessly.
These are only some of the features that MEFedMVVM has to offer. We are working on expanding more functionality. We are also working hard to test as many scenarios as possible but without your feedback and help we cannot cover all of them.
Please let us know if you encounter any issues so that together we can continue building an awesome and easy to use library, and have loads of fun creating cool WPF and SL applications
Download the source