MVVM, Unity and wrapping model objects

Topics: Prism v4 - Silverlight 4, Prism v4 - WPF 4
Sep 3, 2010 at 3:50 PM

Hi

One of the things I'm watching closely in Prism 4 is the development of the MVVM documentation, QuickStarts and Reference Implemenatation. I have used Prism 2 in the past, and really struggled with MVVM combined with Dependency Injection.

In particular, I wasn't able to figure out a strategy of how to create a ViewModel which wraps a particular model object and use constructor injection to resolve dependencies at the same time.

I've been looking at the MVVM QuickStarts and RI in Prism 4 Drop 6, and I haven't yet seen a resolution for this question. Could someone please help me with this?

I'll illustrate with the following example from the RI: The QuestionnaireViewModel creates a collection of QuestionViewModels that wraps each of the Question model objects. For this purpose each QuestionViewModel derived type has a constructor that takes a Question model object as a parameter which is used to create the ViewModel.

My dilemma is this: If I now have some dependencies to add to the QuestionViewModel using constructor injection (I'm using Unity at the moment), I can't find a way to marry that with the above approach of passing in the model object in the constructor.

If I do something like this:

private readonly myDependency;

public NumericQuestionViewModel(NumericQuestion question, IMyDependency myDependency) : base(question)
{
this.myDependency = myDependency;
}

then if I try to resolve the child ViewModel with Unity, then Unity will invariably inject a new instance of the model object (NumericQuestion) into my ViewModel along with the other dependencies, even though I haven't registered the model object with the Unity container. I can't find a way to both provide the model object to wrap in the ViewModel and resolve dependencies when I have hierarchical ViewModels.

I've played around with various options - having multiple constructors, using property injection instead, just newing up the viewModel and passing in the dependencies from the parent to the child, etc. - but none of them feel right to me.

I would like to keep the dependency injection consistent between all my ViewModels and not be forced to use one method of resolving for the parent and another for the children.

I'm aware that Unity 2.0 allows you to provide instances for certain parameters when resolving, but I'm limited to Unity 1.2 at the moment.

Thanks
Riko

Sep 17, 2010 at 9:15 PM

Hi Riko,

As you said there is no example in Prism which shows this scenario. However, you could copy this as a work-item, so the product team can take this into account.

Nevertheless, Prism targets Unity 2.0 that as you stated it can provide solutions for this scenario. 

If your scenario require to use Unity 1.2 the property injection approach seems reasonably fine. Why don't you like this approach?  

Fernando Antivero 
http://blogs.southworks.net/fantivero

 

 

 

Sep 20, 2010 at 4:17 PM

Hi Fernando

Thanks for your input, it is much appreciated. On your points:

  • I'm not convinced anymore that specifying constructor parameters when resolving with Unity 2.0 will work - for one thing, it requires specifying the name of the constructor parameter that you want to provide, which means that it kind of breaks dependency injection.

    For another, it doesn't work in the more general case where you want the parameter to be null when it isn't specified - Unity throws an exception when it doesn't know how to resolve one of the constrcutor parameters (as I discovered when I tried to approximate the constructor parameter passing with child containers and RegisterInstance in Unity 1.2).
  • I did consider using property injection briefly, but it seemed both from the Unity documentation and the DI community that this approach is frowned upon because it isn't as "clean" as constructor injection, i.e. you are specifying an dependency through container-specific attributing as opposed to container-agnostic constructor parameters.

    Even if I used it, it would mean I used one way (constructor injection) for parent ViewModels and another (property injection) for child ViewModels and I would have to adapt my application services to support both constructor injection through Resolve and property injection through BuildUp. I guess I could change everything to use property injection, but that would mean I have to change all my interfaces which currently rely just on specifying ViewModel types which are then resolved as needed.

In the end I adapted the State Management feature in the MVVM RI in the latest drop to Unity, once I figured out what it was doing (with my limited knowledge of MEF and all). It is quite a clever way to get around the limitation of providing data to types that are resolved through a DI container in a disconnected manner.

Still, I can't help but feel that in all the articles and posts I read about MVVM and DI nobody seemed to explain the challenges in doing master-detail MVVM with DI for both the parent and child. Don't know if that means there's something wrong with my design, but it seems to be something that should be quite common.

Sep 20, 2010 at 8:29 PM

Hi,

There is guidance how to implement master-detail MVVM using MEF as DI in the MVVM RI provided by Prism. Nevertheless there is no guidance about your exact scenario. Thus, I'm copying this as a work-item. So that the product team can may take this scenario into account.

Probably there is not an only IoC implementation that fits for all users' scenarios, and it is probably one of the reasons because Prism is agnostic of any implementation. It means that you could use those recommended like Unity 2.0 or MEF as well other of your choice. 

I completely understand your point about property injection and how your code becomes non-container agnostic. But in my opinion, if your scenario requires to use a particular container, should your code be agnostic of it?

I hope this helps,

Fernando Antivero
http://blogs.southworks.net/fantivero

 

 

 

 

Sep 20, 2010 at 8:51 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.