MEFedMVVM changes >> from cool to cooler

MEFedMVVM-Logo2After some discussions with Mr. MEF and a lot of MEF “disassembly and learn” sessions with Reflector, I finally managed to refactor MEFedMVVM and make it utilize more the power of MEF…
Besides this I had a change of Vision for MEFedMVVM. There are loads of awesome MVVM libraries out there, MEFedMVVM should not be competing with these and replicating what these libraries do but add on to them by providing ViewModel injections, Design Time vs Runtime services for Design Time Data, IDesignTimeAware ViewModels, IContextAware services and many other stuff …

I am working with the authors of 2 awesome MVVM libraries and soon we will see a Goldlight version using MEFedMVVM and also Cinch MEFedMVVM enabled :) hopefully we will see more side by side usage of MEFedMVVM with other MVVM libraries.

We rebuilt how MEFedMVVM creates the MEF Composition Container …

Composition in MEFedMVVM

Why this huge code refactoring…

Before, MEFedMVVM relied on CompositionInitializer Satisfy imports which was importing all ViewModels and all Services in your solution… The side effect of this was CompositionInitializer relies on calling CompositionHost.Initialize which can only be called once (in Blend this is a bit hard since blend will re invoke static stuff when you rebuild the project). Besides that maybe you do not want to MIX the MEFedMVVM Composition with your own…

To satisfy an import of all the ViewModels and Services MEFedMVVM was relying on ExportFactory<object, IViewModelMetaData/IServiceMetaData>. As you can see this dictates that all ViewModels and Services where exported as type object… This is done implicitly for you from the ExportViewModelAttribute and ExportServiceAttribute. For ViewModels its ok to be exported as type object since you never rely need a ViewModel to be imported in another ViewModel, if you need this you should reconsider because ViewModels should not be coupled together (unless you have a child vm parent vm relation where you usually would create the Child VM from the Parent VM and pass the instance of the parent)*. But when it comes to services sometimes services need to be injected to other services not just to ViewModels… Now if you export the service as type object you cannot rely do a standard MEF import to get it…

*Having said that if you really really need a VM import do a standard Import and specify the ContractName as VMExport{YourViewModelContractName}. so yea you can still get it via a standard import :)

This problem is now solved by the MEFedMVVMCatalog. The export for services was done as type object so that MEFedMVVM could get all services and check if they are design time or runtime and depending on that inject the proper service in the ViewModel. Now MEFedMVVM catalog does this automatically because when an import is requested, depending on if its runtime or designtime MEFedMVVM will return the proper services. What is cool is that now you can import services using the standard MEF way.

 [ImportingConstructor]
public SelectedUserViewModel(IMyService service)
{ }

OR

[Import]
public IMyService MyService { get; set; }

Bye bye ServiceLocator and hello MEFness :)

As I said before now you can import a Service via standard MEF methods (i.e [Import] or [ImportingConstructor]). This means that your VM does not need to implement the IServiceConsumer anymore or inherit from BaseViewModel. If you are using a framework that already has a BaseViewModel you can continue using it :) If you need a BaseViewModel that simply implements INotifyPropertyChanged MEFedMVVM has NotifyPropertyChangedBase but nothing more… I don’t see MEFedMVVM as a Framework to replace existing MVVM frameworks. MEFedMVVM is now a Framework that can work side by side with any existing MVVM framework that you like.

Being able to specify the imports for the services (and MEF injecting design time or runtime depending on when the VM is created) gives you more flexibility because you can specify things such as CreationPolicy etc. Besides this it means that now Services can be injected into other services etc etc…

So yea now an Export of ViewModel is simple [ExportViewModel(“MyVM”)] or if you need the VM to only be injected at DesignTime because the ViewModel is rendered from a DataTemplate thus the VM instance will already be injected user the DataContextAware VM feature i.e [ExportViewModel(“MyVM”, true)] . Passing true in the export does a bit of magic because it will not create an instance of the VM at runtime but it will still satisy any imports on that VM, at DesignTime it behaves normally i.e it creates the instance of the VM and injects it in the View. This is useful if the VM is being injected via some DataTemplate implicitly.

Bye bye DesignTimeCatalogAttribute for assemblies

Before MEFedMVVM was loading all assemblies that where marked with the DesignTime attribute when in Design Time. The problem with this was that if you forget to put this in your assembly MEFedMVVM would not load your assembly at design time.

The new MEFedMVVM does not require this because it looks at all assemblies checks you is using MEFedMVVM and if the assembly is using MEFedMVVM it loads it… This is done by looking at the reference assemblies of each assembly.

MEFedExportProvider for IContextAware services

THe question you might be asking is, How does MEFedMVVM inject the View to the Services that implement IContextAware?

The answer to this came from Mr. MEF. Create an Export Provider :)

MEFedMVVMExportProvider check if the export being injected implements IContextAware and if it does it sets the correct context (which is the View for IContextAware services). The view is given to the provider by the BasicViewModelInitializer/DataContextAwareViewModelInitializer.

StandardContextInjection

DataContextAwareContextInjection

Overriding the Runtime IComposer

The IComposer API changed… now you need to simple return the Catalog that you want MEFedMVVM to use to resolve the ViewModels and Services used by these ViewModels. I created 2 samples with Custom IComposers, 1 in Silverlight and 1 in WPF.

the API for IComposer now looks like this

  public interface IComposer
    {
        ComposablePartCatalog InitializeContainer();
    }

Conclusion

I hope you like the new MEFedMVVM… I am using this library on a large scale project and I am finding it really awesome. I did not make a release of the library yet so that I do a couple of large projects with this library and make sure that if I need to make API changes I can. Yet hopefully there will not be any more API changes since I think this big refactor made MEFedMVVM really light weight.

Let me know if you have any suggestions or if you hit any bugs. THANKS :)

Download MEFedMVVM from Codeplex: http://mefedmvvm.codeplex.com/