使用WinForms MDI子窗口进行DRY之后

时间:2013-03-26 17:27:04

标签: c# winforms dry mdi

所以我正在使用WinForms在C#中构建一个MDI应用程序。我不能为我的生活弄清楚如何在这种情况下遵循DRY。我正在主菜单条中使用toolstripmenuitems打开新的MDI子项。我重复使用“NewChild”方法作为每个方法的事件处理程序。我试图不必为每个子窗口重复自己,因为它们都遵循相同的模式进行实例化。

我已经研究过泛型并使用了Type类,但它并没有让我真正想要的地方。理想情况下,我只想说

    // etc...
    TypeOfForm = ConfigurationForm;
}

new TypeOfForm();

但我认为这种语言结构不存在。

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();
    }
}

在这种情况下实施DRY的好方法是什么?

2 个答案:

答案 0 :(得分:1)

我会不惜一切代价避免检查类型。它真的使代码混乱。

你真的想在这个公共代码中使用泛型:

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

答案 1 :(得分:0)

这是一个建议:

使用toolstrip对象创建一个字典(或使用Tag属性)及其匹配的表单或表单类型

// you can't use the UI controls before Init, you could use their Tags
// so this should be considered pseudo code
private Dictionary<string, Type> ToolstripForms = new Dictionary<string, Type>
{
    { testConfigurationToolStripMenuItem, typeof(ConfigurationForm) }, 
    { resultsToolStripMenuItem, typeof(ResultsForm) }, 
};

并在您的NewForm方法中:

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

    // some casting and exception handling would go well here
    if (sender != null && ToolstripForms.ContainsKey(sender)) // or sender.Tag?
    {
        newForm = Activator.CreateInstance(ToolstripForms[sender]) as Form;
    }
    ...
}

您可能需要一种方法来确定表单是否已经打开并重点关注而不是每次都打开一个新表单,但这取决于您。一种方法是使用一对对象作为该字典中的值 - 类型和现有实例,尽管其他方法可能看起来更好。