65.9K
CodeProject 正在变化。 阅读更多。
Home

单实例表单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (18投票s)

2007年9月9日

CPOL

2分钟阅读

viewsIcon

72599

downloadIcon

953

MDI 应用程序中的单实例表单

引言

最近在 C# 论坛上,有人问到如何确保 MDI 应用程序中某些窗体的单实例。在我的回复中,我使用了泛型和一个匿名 delegate 来创建一个稍微更通用的解决方案来解决他的问题。在他的回应中,他要求解释这些主题,并且可能撰写(这篇)文章来解释代码。

代码

所以这里是实现中的关键代码片段

private Dictionary<Type, Form> SingleInstanceForms = new Dictionary<Type, Form>();

protected Form ActivateForm<T>() where T : Form, new()
{
    if (!this.SingleInstanceForms.ContainsKey(typeof(T)))
    {
        T newForm = new T();
        // Set up the necessary properties
        newForm.MdiParent = this;
        newForm.FormClosed += new FormClosedEventHandler
            (delegate(object sender, FormClosedEventArgs e)
        {
            this.SingleInstanceForms.Remove(sender.GetType());
        });
        
        this.SingleInstanceForms.Add(typeof(T), newForm);
    }
    Form formToActivate = this.SingleInstanceForms[typeof(T)];
    formToActivate.Show();
    formToActivate.Activate();

    return formToActivate;
}

事实上,这就是强制执行某些窗体单实例所需的所有代码。

Using the Code

要激活(并在需要时创建)所需的窗体,您只需使用以下代码

this.ActivateForm<FormType>();

代码解释

词典

字典是代码的核心,它存储了已在 MDI 父窗口中显示的窗体实例,与其关联的键是窗体的 Type。字典结构自动为我们提供了检查 Form 是否已先前打开的方法。

使用这种方法既有优点也有缺点。其中一个优点已经提到。 缺点是需要额外的代码来管理字典,但是当您考虑到唯一的其他解决方案是循环遍历所有现有窗体时,我认为这并不重要,并且这将花费更长的时间,具体取决于有多少窗体是打开的。 以牺牲一点内存为代价,这是一个不错的解决方案。

ActivateForm

protected Form ActivateForm<T>() where T : Form, new() { }

此方法声明使用泛型来限制传递给方法的类型,约束为 Form, new(),即 T 必须是 Form 类型,并且必须具有默认构造函数。

该方法首先检查窗体的类型是否存在于字典中。 如果不存在,则它创建一个新的窗体实例,设置必要的属性并将其添加到字典中。

匿名委托

代码行如下

newForm.FormClosed += new FormClosedEventHandler
    (delegate(object sender, FormClosedEventArgs e)
        {
            this.SingleInstanceForms.Remove(sender.GetType());
        });

可以将其重写为如下形式

newForm.FormClosed += new FormClosedEventHandler(this.MdiChild_FormClosed);
private void MdiChild_FormClosed(object sender, EventArgs e)
{
    this.SingleInstanceForms.Remove(sender.GetType());
}

Web 上有很多关于匿名 delegate 的优秀解释,因此我不会尝试解释它们。 但是,使用 delegate 而不是单独方法的原因是它使 ActivateForm 方法更紧凑,即在源代码视图中,而不是生成的 IL 中。

历史

  • 2007 年 9 月 9 日:首次发布
© . All rights reserved.