views:

2387

answers:

6

I want to start using dependency injection in my WPF application, largely for better unit testability. My app is mostly constructed along the M-V-VM pattern. I'm looking at autofac for my IoC container, but I don't think that matters too much for this disucssion.

Injecting a service into the start window seems straightforward, as I can create the container and resolve from it in App.xaml.cs.

What I'm struglling with is how I can DI ViewModels and Services into User Controls? The user controls are instantiaed via XAML markup, so there's no oportunity to Resolve() them.

The best I can think of is to place the container in a Singlton, and have the user controls resolve their ViewModels from the global container. This feels like a half-way solution, at best, as it still required my components to have a dependency on a ServiceLocator.

Is full IoC possible with WPF?

[edit] - Prism has been suggested, but even evaluating Prism seems like a big investment, I'm hoping for something smaller

[edit] here's a code fragement where I'm stopped

    //setup IoC container (in app.xaml.cs)
    var builder = new ContainerBuilder();
    builder.Register<NewsSource>().As<INewsSource>();
    builder.Register<AViewModel>().FactoryScoped();
    var container = builder.Build();

    // in user control ctor -
    // this doesn't work, where do I get the container from
    VM = container.Resolve<AViewModel>();

    // in app.xaml.cs
    // this compiles, but I can't use this uc, 
    //as the one I want in created via xaml in the primary window
    SomeUserControl uc = new SomeUserControl();
    uc.VM = container.Resolve<AViewModel>();
+5  A: 

You should take a look at Prism from the p&p team. Here is the site on Codeplex

Jedidja
+1  A: 

Yes, we do it all the time. You can "inject" your ViewModel into the DataContext of the control.

I actually find WPF being even easier to use with DI. Even the dependency objects and properties work with it seamlessly.

Justin Bozonier
+3  A: 
this video gives a nice way to use M-V-VM and get deginer/blend integration - skip to the last 10-20 min for these detailshttp://www.lab49.com/files/videos/Jason%20Dolinger%20MVVM.wmv
Scott Weinstein
+9  A: 

It's actaully very easy to do. We have examples of this in Prism as jedidja mentioned. You can either have the ViewModel get injected with the View or the View get injected with the ViewModel. In the Prism StockTraderRI you will see that we inject the View into the ViewModel. Essentially what happens is that the View (and View interface) has a Model property. That property is implemented in the codebehind to set the DataContext to the value. (this.DataContext = value;). In the constructor of the ViewModel, the View gets injected. It then sets View.Model = this which will pass itself as the DataContext.

You can also easily do the reverse and have the ViewModel injected into the View. I actaully prefer this because it means that the ViewModel no longer has any back reference to the view at all. This means when unit-testing the ViewModel you don't have a view to even Mock. Additionally it makes the code cleaner, in that in the constructor of the View, it simply sets the DataContext to the ViewModel that was injected.

I speak a bit more about this in the video recording of the Separated Presentation Patterns talk that Jeremy Miller and I gave at Kaizenconf. The fist part of which can be found here http://www.vimeo.com/2189854.

Hope this helps Glenn

Glenn Block
That's helpful - I too preferr the 2nd approach where can I find a code sample that does this?
Scott Weinstein
+4  A: 

Hi Scott,

I think you've hit on the issue. The controls need to be injected into their parent rather than created declaratively through XAML.

For DI to work, a DI container should create the class that is accepting dependencies. This means that the parent will not have any instances of the child controls at design time and look something like a shell in the designer. This is probably the recommended approach.

The other "alternative" is to have a global static container called from the control's constructor, or something similar. There is a common pattern in which two constructors are declared, one with a parameter list for constructor injection and the other without parameters that delegates:

// For WPF
public Foo() : this(Global.Container.Resolve<IBar>()) {}

// For the rest of the world
public Foo(IBar bar) { .. }

I would almost call this an antipattern but for the fact that some frameworks leave no other choice.

I'm not even half an expert in WPF so I'm expecting a healthy serving of downmod here :) but hope this helps. The Autofac group (linked from the homepage) might be another place to ask this question. The Prism or MEF sample apps (which include some WPF examples) should give you an idea of what is posssible.

A: 

You should take a look at Caliburn - it's a simple WPF/Silverlight MVC framework with support for full DI. It looks really cool and it lets you use any IoC container you want. There are a couple of examples on the documentation wiki

mookid8000