IContextAware view model stops being context-aware when views are MEF-constructor-injected

May 2, 2012 at 11:34 AM

I have found that if I have a "parent" view model that derives from IContextAware and it uses MEF constructor injection to compose "child" view models and also other views, then it no longer gets a context (the corresponding "parent" view) injected into it (InjectContext is passed null).

Only if the views are removed from the constructor injection does the "parent" view model successfully become context aware.

Is this by design; should I generally not be injecting views into view models (and instead using the ServiceLocator), or is there something else I should be doing to my views and/or view models to make this work properly?

It kind of makes sense that this is by design in a way, because, normally, a context-aware view model should know about a single view (its context). As soon as you start injecting other views into it via its constructor, it all of a sudden doesn't know which context it should be aware of and therefore stops being context-aware.

May 2, 2012 at 12:27 PM

A view model should never have the view referenced. The reason I added this feature was to be able to have UI services. For example the IVisualStateManager. What do you want to do exactly ?

May 2, 2012 at 1:28 PM

I agree.  I am using a view model to spawn/instantiate "child" views.  I thought about using the view-model-first approach (using DataTemplates) per this discussion, but decided against it for the reason mentioned in my comment to the answer to this question on Stack Overflow.  So, going with the view-first approach, I tried to MEF in my views into the view model using constructor injection.  This caused the aforementioned problems.  Now, I'm guessing I need to use the ServiceLocator or, preferably, some sort of view factory service that can be constructor-injected in per this blog.

May 2, 2012 at 1:36 PM

I would always do View first approach. did you have a look at NavigationExtensions in MEFedMVVM (http://marlongrech.wordpress.com/2011/08/27/mefedmvvm-navigationextension/). This enables you to always have a View-First approach.

with this there is no more Parent and Child ViewModels (which I try to avoid as much as possible since its nicer to have atomic ViewModels with 0 dependencies). If there is a ViewModel that needs to create a child you can use INavigationInvokerFactory to create the view and render it somewhere from code, you can of course do this from XAML (in the article I sent you there is how to do it with a button). What this gives you also is the abbility to pass information to the newly created ViewModel in case your "Parent ViewModel" needs to pass something to the "child" viewmodel.

Also one last thing. whenever you need to do something with the View always create a "service" that implements the IContextAware and then inject that service to your ViewModel. that way you keep the ViewModel clean and you can unit test etc (just like you would not have a DB connection code in the viewmodel same applies for view code)

Hope this helps.

May 2, 2012 at 3:28 PM

Been reading through that link - it seems perfect for my situation.  Am going to start trying to implement now, and will let you know how I get on and/or if I have any problems.  Many thanks!

May 2, 2012 at 3:57 PM

I can see that this is very much a work in progress! :)

I am attempting to build the code, but it requires me to install Silverlight runtimes and I need Expression Blend installed for some namespaces, which unfortunately are restricted and will take time to get approval for in my corporate environment that I work.  Are you planning to publish NavigationExtension as a downloadable binary or through NuGet any time soon?

May 2, 2012 at 4:05 PM

Its quite stable I used it for the 3 projects and never had issues...

I am planning to put it on Nuget but need to find the time first... in the meantime here are the dlls 


May 3, 2012 at 9:42 AM

SkyDrive is restricted where I work, too (investment bank - pah!). We can install anything through NuGet, though; so, let me know when you can do as it would be awesome.

Thanks for your help :)