C#/ WinForms:ShowDialog和随后的表格显示

由于我认为与此无关的原因,我有一个或多个与单个实例UI(表单)通信的线程。

在工作线程中,我需要报告进度或输入数据或简单选择。 所有这些都来自用户与UI的交互,当然,对于M $ .NET,所有UI都在主线程中运行。

显然,我需要处理UI(主)线程和工作线程之间的线程同步。 我通过正确validationInvokeRequired和公司来做到这一点。

在那里有一些文章和文章讨论InvokeRequiredIsHandleCreatedIsDisposed等中的不一致和细微之处,所以我不会谈论它。

我只需要说我的UI,即只是一个Form,应该显示为模态无模式 ,具体取决于调用者的愿望。

一个可能只是UI.Warn( "Warning!" )而其他可能是UI.Question( "Make a choice:", options... )

现在考虑下面的M $ DN文档摘录:

Form.ShowDialog方法:

与非模态表单不同,当用户单击关闭表单按钮时,.NET Framework不会调用Close方法…

我从未参加过一个显示为模态的表单,但是他们的实现者说它不会被破坏,在关闭(隐藏)后可能会处于不可用的状态。

但确实如此!

当表单从ShowDialog( )返回时,它的Handle被删除了,因为它相信当再次需要它时,将调用ShowDialog( )并重新创建句柄。

我不知道为什么M $的东西需要这样做,但我只是觉得我能够拥有完全像模态无模式的完全相同的forms而没有问题。 M $ DN docs没有说它是被禁止的(或者我太醉了而无法找到它)!

好吧,最后它是一种相对简单(和肮脏)的方法来修复它。

 var r = ShowDialog( ); // Handle thrown away aftr "ShowDialog()" supposing the // next one will recreate it. if ( !this.IsHandleCreated ) { // Force "Handle" recreation here, while in the main thread, // before any "Show()" happens. CreateHandle( ); } return r; 

它有效,但我想知道它是否应该是达到同一目的的任何体面的方式。 (也许在没有任何限制祖先兼容性包装的东西中编写程序,因为.NET仍然…)

你确定你没有落后吗? 我创建了一个简单的空白表单作为modal dialog,然后使用一个简单的表单进行测试,该表单只有一个显示对话框的按钮。

 public partial class Form1 : Form { private MyDialog theDialog; public Form1() { InitializeComponent(); theDialog = new MyDialog(); } private void button1_Click(object sender, EventArgs e) { theDialog.ShowDialog(); } } 

我可以反复显示对话框,没有任何问题。

现在,如果我调用theDialog.Show() ,关闭它,然后尝试再次显示它,我得到一个ObjectDisposedException

因此,文档是正确的: ShowDialog不会调用Form.Close ,而Show显然会调用。

编辑:

Form.Close的文档告诉您如果要防止表单被销毁,您需要做什么:

您可以通过处理Closing事件并将作为参数传递的CancelEventArgs的Cancel属性设置为事件处理程序来阻止在运行时关闭表单。

通过这些信息和几分钟的思考,拥有一个可以显示为模态或非模态的表单是微不足道的:

 public partial class Form1 : Form { private MyDialog theDialog; public Form1() { InitializeComponent(); theDialog = new MyDialog(); theDialog.FormClosing += new FormClosingEventHandler(theDialog_FormClosing); } void theDialog_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = true; theDialog.Hide(); } private void button1_Click(object sender, EventArgs e) { if (theDialog.Visible) { theDialog.BringToFront(); } else { theDialog.ShowDialog(); } } private void button2_Click(object sender, EventArgs e) { if (theDialog.Visible) { theDialog.BringToFront(); } else { theDialog.Show(); } } }