为什么在MessageBox.Show中使用所有者窗口?

时间:2008-10-12 15:15:24

标签: .net winforms

MessageBox.Show的表单类似MessageBox.Show(ownerWindow,....)。

通过分配所有者窗口我可以获得什么?

8 个答案:

答案 0 :(得分:22)

消息框是一种模式形式,这意味着它的父窗口被禁用,直到消息框被解除。

如果调用的Show()重载不采用所有者标识符,则通常会自动选择父表单。我在文档中找不到描述如何选择该表单的内容,但我的经验是,如果消息框显示在GUI线程内(即主线程或消息泵线程),则活动窗口为该线程被选为父母。

其他线程可能会创建没有父表单的消息框。这可能是一个糟糕的情况,因为它可能位于活动窗口后面,并且用户在关闭程序之前甚至不知道它在那里。为避免这种情况,您可以将应用程序主窗口的句柄传递给Show方法,该方法将在消息框的持续时间内禁用该窗口。


ADDED:我一直在想这个,现在我不太确定。您在下面给出的反射器片段让我觉得可能线程并不重要。 (我的确说我在文档中找不到任何东西!)

我必须回过头来查看代码以确保,但我认为我曾经丢失在主窗体后面的消息框可能实际上是自定义消息框表单,在这种情况下我的经验是错误的,您永远不必提供父表单参数。

很抱歉这个混乱。

我现在的建议是永远不要提供这个参数,除非你需要活动窗口以外的东西作为主要形式。

答案 1 :(得分:3)

设置所有者会导致在消息框打开时禁用所有者。

如果您没有设置所有者,那么用户可以在消息框打开时单击其他内容甚至关闭所有者,然后当消息框关闭并且调用MessageBox.Show之后的代码运行您的程序时可以处于未知状态 - 或者如果所有者已关闭,您现在在不再存在的窗口内运行代码,并且对WinForms或WPF方法的任何调用(或者对WinAPI和任何其他框架也是如此)都可能导致崩溃。

答案 2 :(得分:2)

根据测试和this other answer,.net会自动选择与MessageBox.Show()来电相同的线程中当前关注的窗口。要获得正确的行为,必须确保您在与此窗口相同的线程中显示MessageBox,并且指定MessageBox所在的窗口与owner逻辑关联。 MessageBox仅模态阻止对其启动的线程上的其他Form的输入。这可能与MessageBox如何使自己模态化有关(也许它拦截了针对当前线程的消息,并且只允许一些消息通过除了它自己以外的窗口?)。模态阻止输入的效果是用户将无法将这些窗口或其中的任何控件聚焦在其中并且尝试这样做会产生“叮”声。此外,如果未指定所有者,MessageBox将自动选择当前线程上的活动窗口。如果当前活动窗口来自不同的线程(或不同的应用程序!),MessageBox将没有所有者。这意味着它获得了自己的任务栏条目:它表现为它自己的独特窗口。用户可以在应用程序中引发其他窗口(即使用户无法与它们交互)。您可以获得程序停止响应用户输入而用户感到困惑的情况,因为用户在显示对话框后以某种方式提升了应用程序的主窗口。但是,如果所有者设置正确,尝试抬起主窗口将导致MessageBox被抬起并闪烁。

要使这一切与子窗口完美配合,请确保每个子窗口都设置了Owner属性。如果您拨打ShowDialog()(这会使您的自定义Form模式(并且执行)传递其owner参数,您将通过{{ {1}}到owner))。

现在,大多数winforms编码包括将代码直接编写到MessageBox.Show()子类内的事件处理程序中。在编写winforms事件处理程序时,您可以承担很多事情。首先,您永远不应该在GUI事件处理程序中调用Form作为顶级语句,因为这些处理程序总是在与this.Invoke()子类相同的线程上运行创建于。其次,对于许多(但不是全部)这些处理程序,您可以假设Form具有焦点(因此Form将自动选择它作为其所有者)。例如,当在按钮的Click事件处理程序(可能称为MessageBox.Show())内编写代码时,您可以安全地假设该表单是集中的(因为在另一个表单button1_Click上调用PerformClick()是不好的实践)。但是,即使您的表单没有针对性,也可能会发生Timer.Tick。因此,对于Button,有no need to Invoke() (just like any other winforms event handler) 需要指定Timer.Tick。后一种情况很难被注意到,因为开发人员必须使他们的应用程序不专注,注意到在这种情况下显示的对话框与他们的应用程序聚焦时的行为略有不同。因此,只要您需要使用owner 指定owner,如果可以在窗口未聚焦时触发事件。在致电Invoke()MessageBox.Show()时,此指南适用。

我在这里讨论的大部分内容都是messing around在阅读其他答案时的结果。

答案 3 :(得分:1)

事实证明,窗口所有权不具有传递性。如果您有表单,生成表单,生成MessageBox,MessageBox.Show需要使用ownerWindow参数。原始表单应设置为MessageBox的所有者窗口。

答案 4 :(得分:1)

致电MessageBox.Show(frmMain,"a message","a title")添加表单TextDialog 应用程序的Application.OpenForms()表单集合,与frmMain主表单本身一起。关闭Messagebox后它仍然存在。

当我拨打btnOK_Click()并设置断点时,我刚刚发现了其中的14个。

当我致电frmMain.Close()关闭主表单时,没有任何反应。在关闭所有14个Application.OpenForms之前,frmMain不会关闭,否则你必须调用Application.Exit()

答案 5 :(得分:0)

如果我没错,这会阻止所有者窗口到Focus()直到消息框关闭。

答案 6 :(得分:0)

使用Net Reflector,我刚刚在Messagebox.Show中找到了这段代码:

else if (owner == IntPtr.Zero)
    owner = UnsafeNativeMethods.GetActiveWindow();

因此,如果您没有嵌套所有权(窗口 - (拥有) - >窗口 - (拥有) - > messageBox),则省略ownerWindow会设置您通常会选择的所有者。

答案 7 :(得分:0)

文档似乎暗示owner参数的唯一目的是指定MB_HELP,消息框知道它应该将WM_HELP消息发送到哪个窗口。

http://msdn.microsoft.com/en-us/library/ms645505%28VS.85%29.aspx


哦,刚刚意识到OP是关于.net的 - 我给出了关于winapi的答案 - 对不起!