开发者

Ninject for winforms - does my architecture make this useless?

开发者 https://www.devze.com 2023-01-31 10:12 出处:网络
I\'m trying out Ninject with a winforms app (basically a sketch, I\'m using it sort of like a kata, but nothing so rigorous or specific) in .net 4.

I'm trying out Ninject with a winforms app (basically a sketch, I'm using it sort of like a kata, but nothing so rigorous or specific) in .net 4.

To create the main form, I'm doing something like:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        [...]
        IKernel kernel = BuildKernel();
        Application.Run(kernel.Get<frmMain>());
    }

    static IKernel BuildKernel()
    {
        var modules = new INinjectModule[] 
        { 
            [..modules]
        };

        return new StandardKernel(modules);
    }
}

Fine. This creates a main form and displays it nicely, passing the appropriate interface implementations to the injected constructor.

Now wh开发者_StackOverflowat? My application is an MDI and will have several child windows for manipulating the application model. I don't have a reference to the kernel anymore, so how am I supposed to Get() these forms? The obvious answer is 'pass the kernel to the form' I suppose, but that's a horribly messy strategy and I'm sure that doesn't fit into the philosophy of DI.

I will point out here that the documentation for Ninject 2 sucks. Everything I can find repeats the basic examples, without really explaining how DI using Ninject makes anything easier. The standard of example given isn't complicated enough to make the trouble of coding and creating modules and bindings worthwhile.

edit #1:

Having studied the links kindly provided by Sam Holder, I'm trying out the 'composition root' approach. My architecture now forces all the Forms it uses to derive from a CompositedForm with constructor semantics thus:

    [Inject]
    public CompositingForm(ICompositionRoot CompositionRoot)
    {
        InitializeComponent();
        this.CompositionRoot = CompositionRoot;
    }
    public readonly ICompositionRoot CompositionRoot;

    public CompositingForm() : this(new DummyCompositionRoot()) { }

The second constructor is for the benefit of the Forms Designer, which is stupid and can't understand the form markup unless you provide an empty constructor. Now, every form created using IKernel.Get<AForm>() will (should) have a composition root injected into it.

So, as I am a slow learner - now the question is really 'What should go in this composition root'?


can't you pass a factory for creating the child forms to the forms constructor, and the form uses this to get them, then ninject will wire up the factory dependency when the form is created using the get?

I think you should configure everything in the application root using the DI container and after that the container shouldn't be needed, but I've not really used DI containers in anger, and not NInject at all, so am going on what I've read...

This answer may help


Note: I do not know much about Ninject but i worked with Spring.net that is much more complicated. The principles behind sould be something similar.

Sam Holder answer is excellent if you have several objects of one (injected) type to create (for example CustomerOrderItem).

If you just want to wire your mainform i would sugest that your mdi-frmMain constructor gets parameters for every childwindow it should contain and let Ninject create and insert the childwindows. This way there is no need to Reference NInject outside "class Program ". This is called Constructor-Injection.

Alternatively you can add a method to the form that adds a page to you mdi (MethodInjection).

static void Main()
{
    [...]
    IKernel kernel = BuildKernel();
    var main = kernel.Get<frmMain>();
    main.AddClientForm(kernel.Get<CustomerForm>()) ;
    main.AddClientForm(kernel.Get<InvoiceForm>()) ;
    Application.Run(main);
}


Thanks to João Almeida and Kellabyte I have found a method that is more or less satisfactory:

  • Define a custom Attribute which exposes whatever business rules you care about;
  • Define an implementation of IInjectionHeuristic which recognises this attribute;
  • Use a ViewModelLocator to load modules into the ninject kernel.
0

精彩评论

暂无评论...
验证码 换一张
取 消