WinForms编程 – 模态和非模态forms问题

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

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

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

如果在循环中调用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(); } 

这很危险

当然最好采用模态forms,以避免出现问题。 如果你不想要一个模态forms,那么就不要使它成为模态,使用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  //... } 

首先想到的是这样的事情。 您可以在启动表单2时禁用表单1,然后让表单1处理第二个表单的已关闭事件以重新启用自身。 你不会使用show dialog打开模态2。

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

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

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

然后,你可以做同样的事情:

 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()将使所有formsModal = true 。

根据定义,模态forms是:

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

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

因此,只有当您需要用户的即时协助/互动时,才能使用模态表格。 使用模态forms否则会让你相信你可能会遇到错误的方向。

如果您不希望主表单是MDI容器,那么通过简单的BackgroundWorker类可能使用multithreading是一个解决方案,这是您想要实现的目标的关键。 因此,它看起来像一个设计气味……

  • 你想做什么,除了让你的主要表格响应,等等。
  • 你有什么需要做的?

在解释你必须做的事情时,我们或许可以完全引导你进入正确的,或者至少可能更好的方向。

实际上答案很简单。 尝试

 newForm.showDialog(); 

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