WinForms编程 - 模态和非模态形式问题

时间:2010-05-14 14:18:18

标签: c# forms modal-dialog non-modal

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

Image http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

5 个答案:

答案 0 :(得分: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>
        //...
    }

答案 1 :(得分:3)

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

在我看来,您可以使用将表单#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()会生成所有表单Modal = true

根据定义,模态形式为:

  

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

     

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

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

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

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

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

答案 4 :(得分:-1)

实际上答案很简单。尝试

newForm.showDialog();

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