John Jeffery
John Jeffery

Reputation: 1020

Custom property injection in Castle Windsor for Windows Forms

I have a Windows Forms application which makes use of an MVP pattern. Each view is a WinForms user control and is backed by a presenter which handles non-UI concerns. The application makes use of Castle Windsor, and all views presenters and many other components are resolved via the Windsor Container.

What I would like to be able to do is customise property injection for the user control views. My views don't make a whole lot of use of property injection, but it is occasionally very useful and works well. The problem is, my user controls often contain nested controls, which in turn can contain other nested controls, and property injection is not going to work for these nested controls, because they were not directly resolved via the container.

What I would like to do is to configure property injection for components that inherit from the SWF Control class. In addition to finding properties on the component, I would like to also find properties on nested controls (in the Controls) collection and inject into these nested properties as well.

I know that Castle Windsor is extremely flexible and configurable so this may be possible. I need a bit of a nudge in the right direction though. Is this possible? Has anyone tried to do something similar?

Upvotes: 0

Views: 706

Answers (1)

kmp
kmp

Reputation: 10905

If I have understood your question correctly I think that the only way to achieve what you want is by some sort of poor man's dependency injection because the way the winforms designer generates a method that constructs the various sub-controls you speak of makes it decidedly uncondusive to IoC.

I am not sure you will be able to do property injection but you can utilise the constructor, here is a hair-brained scheme I have just concocted ...

Firstly, create some way to access your windsor container - something like this would probably do the trick:

public static class MyContainer
{
    private static readonly IWindsorContainer _container = Bootstrap();
           
    // I did it like this so that there is no explicit dependency
    // on Windsor - this would be the only place you need to change
    // if you want an alternate container (how much you care about
    // that is up to you)
    public static T Resolve<T>()
    {
        return _container.Resolve<T>();
    }

    private static IWindsorContainer Bootstrap()
    {
        var container = new WindsorContainer();
        container.Install(FromAssembly.This());

        // ... whatever else you need to do here

        return container;
    }
}

Secondly, in the inner controls, where you want some properties injected do something like this (I went for the good ol' ILogger as an example of something you may want injected):

public partial class MyFancyControl : UserControl
{    
    // Constructor to keep the winforms designer happy
    public MyFancyControl() 
        : this (MyContainer.Resolve<ILogger>())
    {
        // Intentionally always blank as this 
        // is an un-unit-testable method
    }
    
    // Constructor that does the actual work
    public MyFancyControl(ILogger logger)
    {
        InitializeComponent();
        Logger = logger;
    }
    
    public ILogger Logger { get; private set; }
}

Note: using the logger raises one of the couple of obvious smells in this - sometimes you don't register such a component with the container at all (usually you have a null logger) so you may need to hook up some sort of mechanism for that but I leave that up to you if you need it or not.

Upvotes: 1

Related Questions