Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use constructor dependency injection to supply Models from a collection to their ViewModels?

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?
like image 464
GraemeF Avatar asked May 10 '10 14:05

GraemeF


People also ask

How does constructor dependency injection work?

When a class requires an instance of a Dependency, you can supply that Dependency through the class's constructor, enabling it to store the reference for future use. Constructor Injection is the act of statically defining the list of required Dependencies by specifying them as parameters to the class's constructor.

Which is the right way to inject the dependency?

Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.


1 Answers

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.

like image 186
Steven Robbins Avatar answered Oct 26 '22 22:10

Steven Robbins