Click here to Skip to main content
15,885,914 members
Articles / Programming Languages / C#

WPF Applications - Part 1: Dependency injected view models

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
16 Feb 2010GPL33 min read 16.2K   8  
This post will be the first in a 3 part series of posts where I will explain how I am currently developing WPF MVVM applications in a testable way with little or no code behind.

Apologies for the delay of this post, we hit crunch time on a project at work and I have been preparing for my sons (yet to be born) nursery on the weekends. Anyway that’s enough excuses. This post will be the first in a 3 part series of posts where I will explain how I am currently developing WPF MVVM applications in a testable way with little or no code behind.

The case study will be a little continuous integration client that will poll the build server and allow me to deploy builds and show me a deployment map of the current deployment status of builds. The use cases are probably going to be irrelevant for most of you so I will try not to focus on them too much.

You can download the source code of this post from here.

Why do we need inversion of control / dependency injection?

Encapsulation, encapsulation, encapsulation, testability and it facilitates the open closed principal. Exactly how it helps with these principals will become clear as I walk through the case study.

Castle container

I am using castles dependency injection framework to host all our dependencies including our view models, so take a few minutes to look at their website.

Let's get started

Create a new WPF application in Visual Studio (I am using VS 2008). Now for simplicity sake, I am going to add a little code behind to Window1.cs. I will explain how to get rid of this in later posts (refactoring out code behind) but for now we just want to get going.

In the constructor of window1.cs, I am going to add the following line of code before the InitializeComponent method call:

C#
DataContext = Container.GetA<IMainViewModel>();

For all you MVVM purists out there (and rightly so!), I will show you how to get rid of this code behind in a separate post.

Container is our own static gateway to the castle micro kernel. We want to abstract this so that our container framework will be unit test friendly and so that we could easily swap out our container implementation without changing our code. Here is a simple implementation of our static container gateway:

C#
public static class Container
    {
        private static IContainer _containerImplementation;

        public static void InitializeContainerWith(IContainer containerImplementation)
        {
            _containerImplementation = containerImplementation;
        }

        public static T GetA<T>()
        {
            return _containerImplementation.GetA<T>();
        }
    }

Now we need to register a MainViewModel implementation with our container. In the App.xaml code behind, add the following code to the OnStartupMethod:

C#
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var container = new CastleKernalContainer();
container.RegisterA<IMainViewModel>(typeof(MainViewModel));
Container.InitialiseContainer(container);
...
}

The CastleKernalContainer implementation is our own IContainer implementation which is basically a wrapper arround the castle kernel:

C#
public interface IContainer
    {
        T GetA<T>();
        void RegisterA<T>(Type type);
    }

public class CastleKernalContainer : IContainer
    {
        private readonly IKernel _castleKernel;

        public MicrokernelContainer():this(new DefaultKernel())
        {
            
        }

        public MicrokernelContainer(IKernel castleKernel)
        {
            _castleKernel = castleKernel;
        }

        public T GetA<T>()
        {
            return (T)_castleKernel.Resolve(typeof (T));
        }

        public void RegisterA<T>(Type implementation)
        {
            _castleKernel.AddComponent(typeof(T).FullName,typeof(T),implementation);
        }
    }

Now in the Window1.xaml, we need the following:

XML
<Window x:Class="DependencyInjection.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Apollo"
    WindowStartupLocation="CenterScreen">
    <Grid>
        <ContentControl Content="{Binding}"/>
    </Grid>
</Window>

Here we are setting the content of our window to be the datacontext. This is where the power of WPF and MVVM form the perfect relationship! We can define a data template for our MainViewModel in the App.xaml as follows:

XML
<application xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 
	xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation 
	x:class="DependencyInjection.App" 
	xmlns:dependencyinjection="clr-namespace:DependencyInjection" 
	startupuri="Window1.xaml">
<application.resources>
<datatemplate datatype="{x:Type DependencyInjection:MainViewModel}">
<mainview />
</datatemplate>
</application.resources>
</application>

Let's now define MainView as a user control:

XML
<usercontrol xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 
	xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation 
	x:class="DependencyInjection.MainView" width="300" height="300">
<grid>
<textblock text="Hello World !" />
</grid>
</usercontrol>

That’s it! You now have a simple dependency injected MVVM framework for any WPF application.

So what happens when we start up the application? Well, not much! You get a window with the text “Hello World” displayed, but it is how we got there that is important!

I deliberately wrote no unit tests for this part as it was not the focus of this post. It was just to get us started. My next post will talk about testable view models in an MVVM context where I will create commands and our application will start loading data from various data sources and I will do this in a BDD style.

This article was originally posted at http://www.sunmetablog.co.uk?p=267

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
United Kingdom United Kingdom
We cannot achieve perfection but we can strive for excellence. Excellence through creativity that pushes innovation, collaboration that facilitates productivity, knowledge that empowers people and persistence that eventually pays off !

Enjoy what you do and do what you enjoy !

Comments and Discussions

 
-- There are no messages in this forum --