Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM and IOC: Handling View Model's Class Invariants

This is an issue I've been struggling with since I started using MVVM, first in WPF and now in Silverlight.

I use an IOC container to manage the resolution of Views and ViewModels. Views tend to be very basic, with a default constructor, but ViewModels tend to access real services, all of which are required for their construction. Again, I use an IOC container for resolution, so injecting services is not a problem.

What does become a problem is passing required data to the ViewModel using IOC. As a simple example, consider a screen that allows the editing of a customer. In addition to any services it might require, the ViewModel for this screen requires a customer object for displaying/editing the customer's data.

When doing any type of (non-MVVM) library development, I consider it an unbendable rule that class invariants be passed via the constructor. In cases where I need context-specific data for class construction time and the class in question is container-managed, I tend to use an abstract factory* as a bridge. In MVVM this seems like overkill, as most ViewModels will then require their own factory.

A few other approaches I have tried/considered included (1) an initialize/load method in which I pass the data, which violates the rule of forcing class invariants through the constructor, (2) passing data through the container as parameter overrides (Unity), and (3) passing data through a global state bag (ugh).

What are some alternative ways to pass context-specific data from one ViewModel to the next? Do any of the MVVM frameworks address this specific problem?

*which can have its own problems, like requiring a choice between a call to Container.Resolve() or not having your ViewModel container-managed. Castle Windsor has a good solution to this, but AFAIK no other framework does.

Edit:

I forgot to add: some of the options I listed are not even possible if you are doing "View First" MVVM, unless you pass data first to the View and then to the ViewModel.

like image 462
Phil Sandler Avatar asked Jun 07 '11 15:06

Phil Sandler


1 Answers

I'm not quite sure what the issue is, so I'll use a simple and contrived example.

Let's say you have a CustomerListViewModel which lists a summary of each customer. When you select a customer, you want to display a CustomerDetailViewModel. This could take either a customer ID, or an ICustomer type which is populated previously in the CustomerListViewModel with the customer details (depending on when you want to load the data for example).

I think what you're asking is what happens if CustomerDetailViewModel also takes a series of services as dependencies which you want to resolve through the container (normally for dependency chains).

As you're doing view model first, you need to instantiate the CustomerDetailViewModel from the CustomerListViewModel, and you want to do so via the container so that the dependencies are injected appropriately.

Therefore, as you mention, you would normally do this through an abstract factory pattern, for example ICustomerDetailViewModelFactory which gets passed as a service to the CustomerListViewModel.

This factory type has a ICustomerDetailViewModel GetCustomerDetailViewModel(ICustomer customer) method. This factory type will require a reference to your IoC container.

When resolving the ICustomerDetailViewModel in your GetCustomerDetailViewModel factory method, you can specify the value you wish to use for the ICustomer constructor parameter when you call Resolve on your container.

For example, Unity has parameter overrides, and see here for Castle Windsor support. Castle Windsor also has a typed factory facility, so that you don't need to implement the concrete factory types, just the abstractions.

So I would go with option 2! We use Caliburn.Micro, it solves a lot of MVVM problems, but I don't know of any frameworks which address this issue.

like image 132
devdigital Avatar answered Sep 24 '22 10:09

devdigital