views:

221

answers:

2

I'm using constructor dependency injection in my WPF application and I keep running into the following pattern, so would like to get other people's opinion on it and hear about alternative solutions.

The goal is to wire up a hierarchy of ViewModels to a similar hierarchy of Models, so that the responsibility for presenting the information in each model lies with its own ViewModel implementation. (The pattern also crops up under other circumstances but MVVM should make for a good example.)

Here's a simplified example. Given that I have a model that has a collection of further models:

public interface IPerson
{
    IEnumerable<IAddress> Addresses { get; }
}

public interface IAddress
{
}

I would like to mirror this hierarchy in the ViewModels so that I can bind a ListBox (or whatever) to a collection in the Person ViewModel:

public interface IPersonViewModel
{
    ObservableCollection<IAddressViewModel> Addresses { get; }
    void Initialize();
}

public interface IAddressViewModel
{
}

The child ViewModel needs to present the information from the child Model, so it's injected via the constructor:

public class AddressViewModel : IAddressViewModel
{
    private readonly IAddress _address;

    public AddressViewModel(IAddress address)
    {
        _address = address;
    }
}

The question is, what is the best way to supply the child Model to the corresponding child ViewModel?

The example is trivial, but in a typical real case the ViewModels have more dependencies - each of which has its own dependencies (and so on). I'm using Unity 1.2 (although I think the question is relevant across the other IoC containers), and I am using Caliburn's view strategies to automatically find and wire up the appropriate View to a ViewModel.

Here is my current solution:

The parent ViewModel needs to create a child ViewModel for each child Model, so it has a factory method added to its constructor which it uses during initialization:

public class PersonViewModel : IPersonViewModel
{
    private readonly Func<IAddress, IAddressViewModel> _addressViewModelFactory;
    private readonly IPerson _person;

    public PersonViewModel(IPerson person,
                           Func<IAddress, IAddressViewModel> addressViewModelFactory)
    {
        _addressViewModelFactory = addressViewModelFactory;
        _person = person;

        Addresses = new ObservableCollection<IAddressViewModel>();
    }

    public ObservableCollection<IAddressViewModel> Addresses { get; private set; }

    public void Initialize()
    {
        foreach (IAddress address in _person.Addresses)
            Addresses.Add(_addressViewModelFactory(address));
    }
}

A factory method that satisfies the Func<IAddress, IAddressViewModel> interface is registered with the main UnityContainer. The factory method uses a child container to register the IAddress dependency that is required by the ViewModel and then resolves the child ViewModel:

public class Factory
{
    private readonly IUnityContainer _container;

    public Factory(IUnityContainer container)
    {
        _container = container;
    }

    public void RegisterStuff()
    {
        _container.RegisterInstance<Func<IAddress, IAddressViewModel>>(CreateAddressViewModel);
    }

    private IAddressViewModel CreateAddressViewModel(IAddress model)
    {
        IUnityContainer childContainer = _container.CreateChildContainer();

        childContainer.RegisterInstance(model);

        return childContainer.Resolve<IAddressViewModel>();
    }
}

Now, when the PersonViewModel is initialized, it loops through each Address in the Model and calls CreateAddressViewModel() (which was injected via the Func<IAddress, IAddressViewModel> argument). CreateAddressViewModel() creates a temporary child container and registers the IAddress model so that when it resolves the IAddressViewModel from the child container the AddressViewModel gets the correct instance injected via its constructor.

This seems to be a good solution to me as the dependencies of the ViewModels are very clear and they are easily testable and unaware of the IoC container. On the other hand, performance is OK but not great as a lot of temporary child containers can be created. Also I end up with a lot of very similar factory methods.

  • Is this the best way to inject the child Models into the child ViewModels with Unity?
  • Is there a better (or faster) way to do it in other IoC containers, e.g. Autofac?
  • How would this problem be tackled with MEF, given that it is not a traditional IoC container but is still used to compose objects?
+1  A: 

Depending on the container can you not specify a parameter (named or otherwise) in your factory's CreateAddressViewModel method?

container.Resolve<IAddressViewModel>(new NamedParameterOverloads() { { "Address", model } };

Depending on the container your factory may have to know the name of the parameter (TinyIoC and Castle afaik), or it may had to be last in the list of constructor dependencies (YMMV depending on containers), which isn't great, but it saves creating a lot of child containers in quick succession, and the GC thrashing that will follow, and you still get DI for all your other dependencies.

Of course this falls down if your VM also has a dependency that requires the same IAddress, in that case a child container is probably the way to go unless you want the VM to have knowledge of the container.

Update: If you're using a subcontainer of a container that uses "last register wins" (which I think Unity does), then you could pass the same child container into your Factory each time, and have your factory simply register the new IAddress - that way you wouldn't be creating a new UnityContainer instance on the heap for each iteration and it should cut down on garbage collections if you're creating lots of items.

Steven Robbins
As you point out specifying parameters doesn't work if any of the dependencies need the model, which has been a showstopper for me.Reusing the child container is a possibility, though.
GraemeF
A: 

The ViewModel sample application of the WPF Application Framework (WAF) shows how you could bring the Model and the ViewModel together. The sample uses MEF as Dependency Injection Framework.

jbe
Looking through the samples I haven't found anywhere that does this - they tend to create a single ViewModel and set the Model on it as the selection changes. Maybe I'm not looking in the right place, can you point me to the class you had in mind?
GraemeF