5

我对 C#.NET 下的表单形式有疑问。假设我有主表单#0(见下图)。此表单代表主应用程序表单,用户可以在其中执行各种操作。但是,有时需要打开额外的非模态表单来执行额外的主要应用程序功能支持任务。假设这是图像中的表格#1。在这个 #1 表单上,可能会打开几个额外的模态表单(图像中的 #2 表单),最后,有一个进度对话框显示较长的操作进度和状态,这可能需要几个几分钟到几个小时。问题是主窗体#0 在您关闭所有模式窗体(图像中的#2)之前没有响应。我需要主窗体#0 在这种情况下可以运行。然而,如果您在表单#2 中打开一个非模态表单,您可以使用模态#2 表单和新创建的非模态表单进行操作。我需要主窗体#0 和窗体#1 及其所有子窗体之间的相同行为。可能吗?还是我做错了什么?也许有某种解决方法,我真的不想将所有 ShowDialog 调用更改为 Show ...

图片 http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

4

5 回答 5

12

模态表单完全符合“模态”的含义,它们禁用应用程序中的所有其他窗口。这很重要,您的程序处于某种危险的状态。您有一大段代码正在等待对话框关闭。如果没有禁用其他窗口,可能会发生非常糟糕的事情。就像用户可以再次启动模式对话框一样,现在您的代码嵌套了两次。或者她可以关闭对话框的所有者窗口,现在它突然消失了。

如果您在循环中调用 Application.DoEvents(),这些正是您会遇到的问题。这是在不禁用其他窗口的情况下让表单表现模态的一种方法。例如:

    Form2 mDialog;

    private void button1_Click(object sender, EventArgs e) {
        mDialog = new Form2();
        mDialog.FormClosed += (o, ea) => mDialog = null;
        mDialog.Show(this);
        while (mDialog != null) Application.DoEvents();
    }

这是危险的。

当然,最好按照设计的方式使用模态形式以避免麻烦。如果您不想要模态表单,那么就不要将其设为模态,请使用 Show() 方法。订阅它的 FormClosing 事件以知道它即将关闭:

    private void button1_Click(object sender, EventArgs e) {
        var frm = new Form2();
        frm.FormClosing += new FormClosingEventHandler(frm_FormClosing);
        frm.Show();
    }

    void frm_FormClosing(object sender, FormClosingEventArgs e) {
        var frm = sender as Form2;
        // Do something with <frm>
        //...
    }
于 2010-05-14T17:26:01.433 回答
3

首先想到的应该是这样的。您可以在启动表单 2 时禁用表单 1,然后让表单 1 处理第二个表单的关闭事件以重新启用自身。您不会使用显示对话框打开模态 2。

现在请记住,从用户的角度来看,这将非常麻烦,您可能会考虑使用 MDI 应用程序将所有窗口放入单个容器中。

于 2010-05-14T14:26:19.890 回答
0

在关闭同一进程空间中的任何模式对话框之前,您的主窗体将不会响应。没有解决办法。

于 2010-05-14T14:28:52.867 回答
0

在我看来,您可以使用 MDI 应用程序设置 Form #0 IsMdiContainer属性设置为 true。

然后,你可以做类似的事情:

public partial class Form0 {
    public Form0 {
        InitializeComponent();
        this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened.
    }

    private void button1_Click(object sender, EventArgs e) {
        Form1 newForm1 = new Form1();
        newForm1.Parent = this;
        newForm1.Show();
    }
}

如您在问题中所述,使用ShowDialog()将使所有表单Modal = true

根据定义,模态形式是:

当表单以模态方式显示时,除了模态表单上的对象外,不会发生任何输入(键盘或鼠标单击)。程序必须隐藏或关闭模态表单(通常是为了响应某些用户操作),然后才能输入到另一个表单。模态显示的表单通常用作应用程序中的对话框。

您可以使用此属性 [( Modal )] 来确定您从方法或属性获得的表单是否已以模态方式显示。

因此,仅当您需要用户的即时帮助/交互时才应使用模态表单。否则,使用模态形式会让人相信您可能走错了方向。

如果您不希望您的主窗体成为 MDI 容器,那么也许使用多线程是一种解决方案,通过一个简单的BackgroundWorker类是您想要实现的关键。因此,在我看来,它就像一种设计气味……

  • 除了使您的主要表单具有响应性等之外,您还想做什么?
  • 你必须做什么?

解释你必须做什么,我们可能能够完全引导你进入正确的方向,或者至少可能是更好的方向。

于 2010-05-14T17:47:09.330 回答
-2

其实答案很简单。尝试

newForm.showDialog();

这将打开一个新表单,而父表单无法访问。

于 2012-08-05T16:27:44.523 回答