Archive for the ‘WPF’ Category

Dependency Injection in WPF Bindings

Monday, December 1st, 2008

Creating clean testable code is one of the major challenges when creating complicated, composite user interfaces.  To help with this a variety of patterns have cropped up including MVC, MVP, and most notably for WPF the MVVM pattern.   These patterns work fine for the most part at least until your view gets a little bit too complicated.  What is a programmer supposed to do with the added complexity?  You should be separating common logic out into self contained controls, each with their own view models.  This is easier said then done, as you need to make sure that you provide view models for each of the controls your view implements.  While this is probably the more accepted way of doing things, it leads to a lot of code noise and increased complexity when writing tests for your main view model.

There is another way and you can get there by using the Markup Extensions that are available to exend WPF.  Because I’m a bit to lazy to create my own custom binding extension, I used one that I found here http://www.hardcodet.net/2008/04/wpf-custom-binding-class .  This fellow has already explored custom bindings and has created an easy to use base class for creating and manipulating custom WPF bindings.

With this class in place it is a fairly trivial operation to create a databinding class that utilizes your favorite dependency injector.  For this sample I am using StructureMap.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    /// <summary>
    /// Binds to a dependency injected object
    /// </summary>
    public class DIBinding : BindingDecoratorBase
    {
        /// <summary>
        /// The type we are looking for
        /// </summary>
        public Type Type { get; set; }
 
        /// <summary>
        /// The key if applicable
        /// </summary>
        public string Key { get; set; }
 
        public override object ProvideValue(IServiceProvider provider)
        {
            //use DI to get the value
            if(Type == null)
                throw new InvalidOperationException("You must specify a type for this binding");
 
            Source = String.IsNullOrEmpty(Key) ? ObjectFactory.GetInstance(Type) : ObjectFactory.GetNamedInstance(Type, Key);
 
            return base.ProvideValue(provider);
        }
    }

Once we have created this binding helper we can use it in any xaml file provided that we include the proper namespaces of course.

1
<TreeView ItemsSource="{DataBinding:DIBinding Type=MainNav:IMainNavigationMenu, Path=MenuItems}" />

Use of dependency injection in your xaml files should be limited to where it is appropriate.  Of course it is not appropriate to do you whole application in this manner, but for certain controls it can lead to a much cleaner more testable view model for rest of your code.