Search code examples
c#winformsdrymdi

Following DRY with WinForms MDI Child windows


So I'm building an MDI application in C# using WinForms. I can't for the life of me figure out how to follow DRY in this scenario. I'm opening new MDI children using toolstripmenuitems in my main menu strip. I've reused "NewChild" method as the event handler for each of these. I'm trying not to have to repeat myself for each child window, as they all follow the same pattern for instantiation.

I've looked into generics and using the Type class, but it doesn't really get me where I want. Ideally I'd love to just say

    // etc...
    TypeOfForm = ConfigurationForm;
}

new TypeOfForm();

But I don't think such lose language constructs exist.

public partial class MainForm : Form
{
    private AboutForm aboutForm;
    private ConfigurationForm configForm;
    private ResultsForm resultForm;
    private LogForm logForm;

    private void NewChild(object sender, EventArgs e)
    {
        Form newForm;

        if (sender == testConfigurationToolStripMenuItem)
        {
            if (configForm == null)
            {
                configForm = new ConfigurationForm();
            }
            newForm = configForm;
        }
        else if (sender == resultsToolStripMenuItem)
        {
            if (resultForm == null)
            {
                resultForm = new ResultsForm();
            }
            newForm = resultForm;
        }
        else if (sender == logToolStripMenuItem)
        {
            if (logForm == null)
            {
                logForm = new LogForm();
            }
            newForm = logForm;
        }
        else
        {
            return;
        }

        newForm.MdiParent = this;
        newForm.Disposed += new EventHandler(ChildDisposed);
        newForm.Show();
    }
}

What would be a good way to implement DRY in this kind of situation?


Solution

  • I would avoid checking types at all costs. It really clutters code.

    You really want to use generics for this common code:

    // for multiple instance forms (and instantiating a "singleton" form)
    private void AddNewChild<T>() where T: Form
    {
        T newForm = new T();
        newForm.MdiParent = this;
        newForm.Disposed += new EventHandler(ChildDisposed);
        newForm.Show();   
    }
    
    // for "singleton" forms
    private void ActivateChild<T>() where T: Form
    {
        // off-the-cuff guess, this line may not work/compile
        var child = this.MdiChildren.OfType<T>().FirstOrDefault();
    
        if (child == null) 
        {
            AddNewChild<T>();
        }
        else
        {
            child.Show();
        }
    }
    
    // usage
    logToolStripMenuItem.Click += (s,e) => ActivateChild<LogForm>();
    testConfigurationToolStripMenuItem.Click += (s,e) => ActivateChild<ConfigurationForm>();
    multipleInstanceFormMenuItem.Click += (s,e) => AddNewChild<FormX>();
    ...