Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doing dependency injection right in a WinForms application with subforms

Let's say a main form have a few menu items. Each menu item will show another form. Is the following code a good way to do dependency injection in this scenario?

public class MainForm: Form {
  private IAboutForm _aboutForm;
  private IOptionsForm _optionsForm;
  private IDownloadsForm _downloadsForm;

  MainForm(IAboutForm aboutForm, IOptionsForm optionsForm, IDownloadsForm downloadsForm) { // add as many form dependencies as required
    _aboutForm = aboutForm;
    _optionsForm = optionsForm;
    _downloadsForm = downloadsForm;

    InitializeComponent();
  }

  private void AboutMenuItem_Click(object sender, System.EventArgs e) {
    _aboutForm.ShowDialog(this);
  }

  private void DownloadsMenuItem_Click(object sender, System.EventArgs e) {
    _downloads.Show();
    _downloads.BringToFront();
  }

}
like image 359
fxam Avatar asked May 04 '26 12:05

fxam


1 Answers

This works fine as-is, but it doesn't extend well - your constructor will become huge after a while if you continue to add forms. If you never add any more, then you are probably fine. If you know you will add more, or don't think you will but end up doing so, you may want to inject an IFormFactory of some sort instead, like so:

IFormsFactory formsFactory;
MainForm(IFormsFactory formsFactory)
{
    _formsFactory = formsFactory;
}

then you can just create the dependent forms as needed:

private void AboutMenuItem_Click(object sender, System.EventArgs e) {
    IAboutForm aboutForm = _formsFactory.CreateAboutForm();
    aboutForm.ShowDialog(this);
}

There's several ways you can go about this. You can keep all the forms as member variables, and just use the injected factory to create them in the constructor. This is good if performance is a concern, and you need just a single instance for each for the life of the program.

Note that you can add "construction" parameters to the factory.CreateXXX() call if needed too.

Inside the factory, it will know how to create each form. If you use an IoC container, you don't even need to create a concrete of the IFactory interface. If there's special logic to creating a form though, then you may want to create a concrete instead and resolve the injected IFactory to that concrete.

There's quite a bit more that can be said about this, but this is a good starting point I think. Hope it helps.

like image 153
Gjeltema Avatar answered May 07 '26 01:05

Gjeltema