views:

456

answers:

1

I have a WPF UserControl that I'd like to inject dependencies into. What's the best way to do this with Ninject?

To take a concrete example: I have a UserControl called MapView, and I want to inject an instance of my IDialogueService into it, via either constructor or property injection. Currently, I'm not using any dependency injection, and my control is created in XAML:

<Window x:Class="GameWindow" ...>
    <Grid Name="root">
        <MapView x:Name="mapView" ... />
        <!-- other stuff here -->
    </Grid>
</Window>

Creating an IKernel, and binding the IDialogueService, is straightforward enough. But I'm stuck on how to use the kernel to inject dependencies into my MapView. I'm still a total newbie at Ninject, so maybe there's something obvious that I'm missing.

I can think of several ways to solve this:

  1. Instantiate the MapView in code. Remove the <MapView ... /> from the XAML, and instead add this to GameWindow's constructor:

    public GameWindow(IKernel kernel) {
        root.Children.Add(kernel.Get<MapView>());
    }
    

    Downsides: extra complexity from not using XAML; GameWindow has a dependency on IKernel.

  2. Keep the instantiation in XAML, and use property injection instead:

    public GameWindow(IKernel kernel) {
        kernel.Inject(mapView);
    }
    

    Downside: Ninject docs say that Inject() "should not be used for most cases", so I don't even know if it does what I think it does, or whether it makes sense to use it here. And GameWindow still has a dependency on IKernel.

  3. Add injectable parameters/properties to GameWindow that pass the values along to the MapView (probably via properties on MapView), and then use Get<GameWindow>(). Downside: now I'm manually passing dependencies all over the place, which is what a DI framework is supposed to automate for me.

  4. After instantiating the GameWindow, walk the logical tree and call IKernel.Inject() on everything. Downsides: again, I don't know whether Inject() does what I think it does, or whether it's appropriate here. Caller must remember to do the walk-the-visual-tree-and-inject thing after instantiating a GameWindow.

Is there a better way to do this? Maybe a WPF extension for Ninject that lets me do a Get<GameWindow>(), and automatically walks the logical tree for me (as in #4), doing property injection on everything? If such a thing doesn't exist, would it be possible for me to write it?

How do you guys approach using Ninject with WPF? Do you use any of the above approaches (and if so, can you share up/downsides I don't know about)? Do you have better approaches?

+2  A: 

1) is best. You'll also find it's a convenient entry point for Mapview functions.

Also, rather than passing in the kernel, just do kernel.Get< GameWindow>() and [inject] MapView in GameWindow.

Ray
Injecting the control itself never even occurred to me, but now it seems obvious. Thanks!
Joe White