1

Running into a knowledge gap, been out of WinForms for so long, unsure if i am doing this correctly for Castle Windsor.

For the last 5 years i have developing ASP.Net applications (WebForms, MVC, etc). I now have a project where a web interface is not a viable solution, yet. So we are doing it with WinForms.

With Asp.Net, i would have just set up the Castle Windsor Container, CWC, static class and everything would have taken care of itself for Dependency Injections, etc.

I am having some issues when it comes to WinForms. I evidently cant implement the same rules for Dependency Injection that i did for the WebForms developments.

Current Implementation:

Program.cs:

static void Main () {
    Initialize();

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault( false );

    var form = CWC.Resolve<frmMain>();
    Application.Run( form );

}

public static void Initialize ( string log4netPath = null ) {
    var container = new WindsorContainer();

    container.Kernel.ComponentModelCreated += ( s => {
        if ( s.LifestyleType == LifestyleType.Undefined )
            s.LifestyleType = LifestyleType.PerWebRequest;
    } );

    container.Install(
        new CoreManagerInstaller() , 
        new DomainInstaller() ,
        new RepositoryInstaller() ,
        new ServiceInstaller()
    );

    //Installer for MVC framework -- Must be done after other installers on its own.
    container.Install( new AppInstaller() );

    if ( log4netPath != null ) {
        //container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );
    }

    CWC.Init( container );
}

AppInstaller:

public class AppInstaller : IWindsorInstaller {

    #region IWindsorInstaller Members

    public void Install ( IWindsorContainer container , IConfigurationStore store ) {
        container.Register(
            Classes.FromThisAssembly()
                .BasedOn<CIMForm>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<CIMTabControl>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<CIMTabPage>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<UserControl>().LifestyleTransient() );
    }

    #endregion
}

All the above is nothing new or problematic atm.

The problem child is the UserControl i am trying to reference Interfaces form other libraries. In WebForms i would have just dropped the Property signature and started using in the Event/Methods i needed it.

As such:

public partial class ClientInformationControl : UserControl {
        public IServerRepository ServerRepository { get; set; }

        private void ClientInformation_Load ( object sender , EventArgs e ) {
            var servers = ServerRepository.Find().Select( s => new { Key=s.Id , Value=s.Name } );
            cboServers.Items.AddRange( servers.ToArray() );

        }
}

But ServerRepository never gets instantiated in this design. I have to manually call CWC.Resolve<IServerRepository>() in order for the property to have the information in need.

Is there a way to make it so that ServerRepository is automatically (auto-magically) filled with the object data from the container?

Tried doing public ClientInformationControl(IServerRepository serverRepo){} but the assignment did not persist past the constructor, so when the Control.Load event was triggered the ServerRepository Property has been emptied out.

GoldBishop
  • 2,820
  • 4
  • 47
  • 82
  • `I now have a project where a web interface is not a viable solution, yet. So we are doing it with WinForms.` - just a side comment. winforms is not recommended for any new projects. It is a really ancient technology that has been replaced by much more modern, scalable, customizable, faster, resolution-independent, vector-based, hardware-accelerated, beautiful, XAML-based technologies (which are also much closer to the Web paradigm than winforms, and enable really cleaner patterns). You should really reconsider your decision. I don't intend to offend anyone with this comment, please. – Federico Berasategui Feb 07 '14 at 20:14
  • 1
    Thank you for the nonconstructive comment. There are reasons for doing it in various frameworks, and this happens to be one that their infrastructure requires and can handle. – GoldBishop Feb 07 '14 at 20:41

1 Answers1

1

The problem with usercontrols is that they do no get resolved by the DI framework (DIF).

You havent posted the code of your winform, but I assume the designer code looks something like this:

private void InitializeComponent()
{
    this.ClientInformationControl1 = new ClientInformationControl();
    [...]
}

This is because you probably dragged the user control onto the form, so the DIF does not know about it.

There are multiple ways to work around this:

1: Don't use the designer to add usercontrols, but register them and let the DIF resolve them for you. You can do this by adding them to the constuctor parameters, as property, or resolve the usercontrol whenever you need it.

2: Give the parent that is resolved (the form) a IServerRepository dependency. But then you'll have to manually wire the IServerRepository into the usercontrol tho...

Ron Sijm
  • 8,490
  • 2
  • 31
  • 48
  • I have not gotten to the state of cleaning the Designer code out and only using the code i need from the designer. Since my other DLL projects contain an installer so i dont have to do one massive DIF registry, would there be a simpler way of doing this "auto-registry"? In MVC, i did something like `container.Register( Classes.FromThisAssembly().BasedOn().LifestyleTransient());` to get all the controllers in for Resolve. Would there be a similar way for WinForms? – GoldBishop Feb 14 '14 at 18:48
  • Well, you can still use `Classes.FromThisAssembly()` to register everything. I believe all user controls inherent from System.Windows.Controls.Control, so you can register them based on that. Problem is though that in MVC the controllers get resolved by convention, by a ControllerFactory factory. Winforms does not have something like that. – Ron Sijm Feb 15 '14 at 11:31
  • So i could do something similar to the IController if i had a single derived control class for these controls, correct? Say all the controls used in the application inherited `IAppControl`, or `AppControl` for common property values. Then my DIF registry would be `Classes.FromThisAssembly().BasedOn`, or equivalent for class? – GoldBishop Feb 17 '14 at 17:28
  • Yes, basically. Thats why I mentioned I think all usercontrols derive from `System.Windows.Controls.Control`, so you could try using that. But still, even if you register them, you cannot just drag / drop them onto the form as usual, since that would just create a new instance of the object, instead of resolving it. – Ron Sijm Feb 17 '14 at 18:03
  • Thank you for the education and assistance. – GoldBishop Feb 17 '14 at 21:14
  • Have not actually implemented this yet, project got back-burnered and a SharePoint implementation was required. As soon as i can get back to this project, i will definitely attempt the implementation. The reasoning and design described is sound, but everything looks good on Paper ;) – GoldBishop Apr 09 '14 at 21:33