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?
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>();
...