2010-05-14 95 views
6

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

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

+2

您是否要求创建一个仅适用于其他表单之一的表单? – SLaks 2010-05-14 14:21:14

+0

我希望主窗体#0在有一些额外的模态子窗体(#2)打开非模态窗体#1时会保持响应。 – Povilas 2010-05-14 14:29:08

回答

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> 
     //... 
    } 
+0

谢谢你的回答,我想我可以使用一个单独的GUI线程,因为主窗体#0和窗体#1基本上都是自己的生活,并且不会互相影响。表格#1可能甚至是一个单独的应用程序。 我不能将ShowDialog()更改为Show(),因为我需要模态窗体,但只能在窗体#1上下文中使用。用户无法继续使用表单#1(仅适用于表单#1),直到从表单#1打开的模式表单未关闭。 – Povilas 2010-05-20 06:57:23

3

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

现在请记住,从用户角度来看,这将是相当繁琐的,你可以看看做一个MDI应用程序来获得一个容器内的所有窗口。

0

直到在同一进程空间中的任何模态对话框都关闭后,您的主窗体才会响应。这没有工作。

0

它看起来对我来说,你可以使用MDI应用程序设置窗体#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类是你想实现的关键。因此,在我看来就像一个设计的气味......

  • 什么是你想做的事,除了让你的主要形式响应的,等
  • 你这是什么做的?

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

+0

谢谢你的回答,我会尽力解释更好。 MDI或将ShowDialog()更改为Show()不会为我解决这个问题,因为我需要模态窗体(自定义数据编辑器),并且用户无法继续,直到他没有完成当前的窗体为止,但我需要模式才能工作在形式#1上下文中。在表单#1上,用户正在处理稍后在主窗体#0上需要的一些数据。基本上,主要形式#0和形式#1生活在他们自己的生活中,形式#1甚至可以是独立的应用程序。 #0从少数单身物体获取数据,其中#1形式正在更新数据。 – Povilas 2010-05-20 06:48:55

+0

一年中有一半时间一切正常,但由于新的需求急速增加,我有一种情况,一个自定义数据编辑器的工作可能需要几个小时。所以我认为我可以使用Hans Passant的建议 - 一个单独的GUI线程。并通过少数单例对象同步数据。 – Povilas 2010-05-20 06:49:19

-1

其实答案很简单。尝试

newForm.showDialog(); 

这将打开一个新窗体,而父窗体不可访问。