C#/ WinForms:ShowDialog和随后的表格显示
由于我认为与此无关的原因,我有一个或多个与单个实例UI(表单)通信的线程。
在工作线程中,我需要报告进度或输入数据或简单选择。 所有这些都来自用户与UI的交互,当然,对于M $ .NET,所有UI都在主线程中运行。
显然,我需要处理UI(主)线程和工作线程之间的线程同步。 我通过正确validationInvokeRequired
和公司来做到这一点。
在那里有一些文章和文章讨论InvokeRequired
, IsHandleCreated
, IsDisposed
等中的不一致和细微之处,所以我不会谈论它。
我只需要说我的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(); } } }