37
votes

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 discussion.

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 struggling with is how I can DI ViewModels and Services into User Controls? The user controls are instantiated via XAML markup, so there's no opportunity to Resolve() them.

The best I can think of is to place the container in a Singleton, 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 fragment 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>();
8
Glenn Block has done some introductions to Prism through podcasts and blog posts - I don't think there's that much of an investment in evaluating it.Jedidja
Scott, what is the "big" investment you are seeing? Are you guessing this, or have you actually looked at it? Prism is designed in such a way that you can use only the parts you need, there's no big commitment. I'd be happy to chat with you offline about this.Glenn Block

8 Answers

17
votes

It's actually 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 code-behind to set the DataContext to the value, for example: 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 actually 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 talk a bit more about this in the video recording of the Separated Presentation Patterns talk that Jeremy Miller and I gave at Kaizenconf. The first part of which can be found here https://vimeo.com/2189854.

10
votes

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&lt;IBar&gt;()) {}

// 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 possible.

4
votes

We are experiencing a similar issue. We are looking forward for a solution that will provide Design time support under Expression Blend 2.0 (Strong Type). Plus we are looking forward for a solution to have some Mock+Auto-Generated data sample available under Expression Blend.

Of course, we are looking also to have all those thing work using an IOC pattern.

Paul Stovell as an interesting article to start with: http://www.paulstovell.com/blog/wpf-dependency-injection-in-xaml

So I try a couple thing to add more valuable design time support for Binding and mocking object at Design time, right now I’m having most of my problem related to get a strong typed connection made between the View (code) to the ModelView(Xaml), I tried a couple scenario:

Solution 1 : Using Generic to create the View

public class MyDotNetcomponent<T> : SomeDotNetcomponent 
{
    // Inversion of Control Loader…
    // Next step add the Inversion of control manager plus
    // some MockObject feature to work under design time
    public T View {Get;}
}

This solution does not work since Blend does not support Generic inside is design surface but Xaml do have some, well work at runtime but not at design;

Solution 2: ObjectDataProvider

<ObjectDataProvider ObjectType="{x:Type CP:IFooView}" />
<!-- Work in Blend -->
<!—- IOC Issue: we need to use a concrete type and/or static Method there no way to achive a load on demande feature in a easy way -->

Solution 3: Inherit ObjectDataProvider

<CWD:ServiceObjectDataProvider ObjectType="{x:Type CP:IFooView}" />
<!-- Cannot inherit from ObjectDataProvider to achive the right behavior everything is private-->

Solution 4: Create a mock ObjectDataProvider from scratch to the job

<CWD:ServiceObjectDataProvider ObjectType="{x:Type CP:IFooView }" />
<!-- Not working in Blend, quite obvious-->

Solution 5: Create a Markup Extension (Paul Stovell)

<CWM:ServiceMarkup MetaView="{x:Type CP:IFooView}"/>
<!-- Not working in Blend -->

Just to clear one point. When I said “not working in blend”, I mean that the Binding dialog is not usable and the designer needs to handwrite the XAML by itself.

Our next step will probably be to take the time to evaluate the ability to create a plug-in for Expression Blend.

3
votes

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.

3
votes

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

1
votes

Glen Block (see above) mentions that a common approach is to design your MVVM solution to use the DataContext as the place where you can "resolve" your View Model in the View. Then you can use design extensions from expression blend 2008 (note that you don't need to be using the expression blend design tools to take advantage of this). For example:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" 
d:DataContext="{d:DesignInstance Type=local:MyViewModelMock, IsDesignTimeCreatable=True}"

In your view you can have a property getter that casts your DataContext to the type that you expect (just to make it easier to consume in the code-behind).

private IMyViewModel ViewModel { get { return (IMyViewModel) DataContext; } }

Don't forget to use an interface so that your views are easier to test, or to help you inject different runtime implementations.

In general, you should not be resolving things from the container all over the place in your solution. It is actually considered bad practice to pass your container around in every constructor, or to make it globally accessible. (You should look up discussions of why "Service Locator" strategies constitute an "Anti-Pattern").

Create a public View constructor with explicit dependencies that the container (e.g. Prism Unity or MEF) can resolve.

If necessary, you could also create an internal default constructor to create a mock of your view model (or a real one for that matter). This protects against inadvertent use of this "design constructor" externally (in your "Shell" or wherever). Your test projects can also use such constructors using the "InternalsVisibleToAttribute" in "AssemblyInfo". But of course, that usually isn't necessary since you can inject your mocks using the full dependency constructors anyway, and because the majority of your tests should be focusing on the ViewModel in the first place. Any code in the View should ideally be quite trivial. (If your View requires a lot of testing, then you might want to ask yourself why!)

Glen also mentions that you can inject Views into View Models, or View Models into Views. I much prefer the latter because there are perfectly good techniques for decoupling everything (use of Declarative Binding, Commanding, Event Aggregation, Mediator patterns, etc.). The View Model is where all the heavy lifting will be done to orchestrate core business logic. If all of the necessary "binding" points are provided by the View Model, it really shouldn't need to know ANYTHING about the View (which can mostly be wired up to it declaratively in the XAML).

If we make the View Model agnostic to the source of user-interaction, that makes it much easier to test (preferably first). And it also means that you can easily plug in ANY view (WPF, Silverlight, ASP.NET, Console, etc.). In fact, to ensure that appropriate decoupling has been achieved, we can ask ourselves if a "MVM" (Model-ViewModel) architecture could work in the context of, say, a Workflow service. When you stop to think about it, most of your unit tests will probably be designed on that premise.

0
votes

I think You have to Decide on View First or Viewmodel First then as given the other answer it Can be decide.. There are several open source framework does it same . I use Caliburn where ViewModel first is taken and its really good approach

0
votes

I wrote an very light framework where a ViewModel is resolved at runtime by using a IoC (Unity) as a markup extension.

The framework allows for writing XAML without a code behind but still lets you have routed commands, data binding, and event handlers.

In any case, I don't think you need the loose XAML in your case, but if you look at the code (http://xtrememvvm.codeplex.com), it might turn out that you can use some of the code to solve your own issues with injecting View Models and Services.