49

我最近发现默认情况下 MessageBoxes 不是默认显示时最顶层的表单,我想知道是否有人知道您不希望消息框显示在其他窗口顶部的任何情况?

当我在加载应用程序时开始显示启动画面时,我发现了这个问题,看起来我的程序仍在运行,但MessageBox启动画面后面有一个等待输入。启动画面显示在不同的线程上调用消息框的线程,所以我想这就是它没有出现在启动画面上方的原因;但这仍然不能解释为什么 MessageBox 默认没有MB_TOPMOST标志?

编辑

为了更好地澄清:最后我不得不做类似的事情来制作一个消息框,代码并不完全正确,因为从内存中写入)

[DllImport("User32.dll")]
private int extern MessageBox(windowhandle, message, caption, flag);
public static void MessageBox(windowhandle, string message, string caption)
{
    MessageBox(windowhandle, message,caption, MB_TOPMOST);
}
4

5 回答 5

85

如果您可以获得对话框应该出现在其顶部的窗口的句柄或引用,则建议的解决方案将起作用。但是,这可能并不总是可能或容易实现:

  • 该窗口是一个启动屏幕,不应与您的业务逻辑紧密耦合
  • 该窗口是由另一个类或库而不是当前类或库创建的
  • 该窗口不受您的控制,即来自第三方(本机)库

在这种情况下,您可以使用 Win232 MessageBoxAPI User32.dll,但也可以使用更简单的托管解决方案:

MessageBox.Show(new Form { TopMost = true }, "Hello, I'm on top!");

代码new Form { TopMost = true }将创建一个带有属性的隐藏表单,该MB_TOPMOST属性由消息框对话框窗口继承。结果,它将出现在所有其他窗口的顶部。使用new Form()内联没有副作用,没有视觉外观,它会被垃圾收集器正常销毁。

注意:如果您还没有在表单中,请不要忘记命名空间,这是System.Windows.Forms.MessageBox,不是System.Windows.MessageBox!(谢谢,user1)。

于 2014-05-18T16:00:36.243 回答
35

在应用程序的最顶部显示 MessageBox

代码

//Should be MessageBox.Show() below
MessageBox.Show(this, "My top most message");

MB_TOPMOST默认的原因

如果 MB_TOPMOST 将是默认值,那么MessageBox它将以“系统模式”模式显示,并且它将恰好在该表单的顶部,副作用是“系统模式”模式将导致MessageBox阻止窗口,直到消息被关闭通常它将是“应用程序模式”模式。

参考链接

  1. MSDN 论坛 - 如何将 MessageBox 显示为最顶层窗口
  2. SO - 当应用程序最小化到托盘时 C# MessageBox 到前面
于 2013-04-19T13:20:37.613 回答
6

显示时MessageBox提供其所有者作为第一个参数。例如,从Form实例调用中调用时:

MessageBox.Show(this, "Message");

提供对拥有它的窗口的引用作为第一个参数。

消息框(以及一般的模态表单)不会出现在应用程序的所有窗口之上。它们只出现在它们的主人之上。如果您希望您的消息框(或其他模式表单)位于启动屏幕顶部,请将其所有者设置为启动表单实例。

于 2013-04-19T13:05:38.283 回答
3

我尝试粘贴更完整的代码片段,它肯定有效

    [CLSCompliant(false)]
    [DllImport("user32.dll", EntryPoint = "MessageBox")]
    public static extern int MessageBoxUser32(int hWnd, String text, String caption, uint type);

    const uint MB_TOPMOST = 0x00040000;
    const uint MB_OK  = 0x00000000;
    const uint MB_OKCANCEL = 0x00000001;
    const uint MB_ABORTRETRYIGNORE = 0x00000002;
    const uint MB_YESNOCANCEL = 0x00000003;
    const uint MB_YESNO = 0x00000004;
    const uint MB_RETRYCANCEL = 0x00000005;

     public static void ShowMessageBox(string message, bool topMost = true
        , string title = null, MessageBoxButtons buttons = MessageBoxButtons.OK)
    {
        if(topMost)
        {
            uint mbv = MB_TOPMOST;

            if (buttons == MessageBoxButtons.OK)
                mbv |= MB_OK;
            if (buttons == MessageBoxButtons.OKCancel)
                mbv |= MB_OKCANCEL;
            if (buttons == MessageBoxButtons.AbortRetryIgnore)
                mbv |= MB_ABORTRETRYIGNORE;
            if (buttons == MessageBoxButtons.YesNoCancel)
                mbv |= MB_YESNOCANCEL;
            if (buttons == MessageBoxButtons.YesNo)
                mbv |= MB_YESNO;
            if (buttons == MessageBoxButtons.RetryCancel)
                mbv |= MB_RETRYCANCEL;

            MessageBoxUser32(0, message, title == null ? string.Empty : title, MB_TOPMOST);
        }
        else
        {
            MessageBox.Show(message, title == null ? string.Empty : title, buttons);
        }
    }
于 2017-12-28T07:05:11.040 回答
2

上面给出的答案显然是正确的,减去它需要在对象 new Form 上调用 System.iDisposable.Dispose 的事实。

MessageBoxButtons buttons = MessageBoxButtons.YesNo;
MessageBoxIcon icon = MessageBoxIcon.Error;
string message = Resources.ResourceManager.GetString("MESSAGE");
string caption = Resources.ResourceManager.GetString("TITLE");
DialogResult result;
Form form;
using (form = new Form())
{
    form.TopMost = true;
    result = MessageBox.Show(form, caption, message, buttons, icon);
}
if (result == DialogResult.Yes)
{
    // do something with the result
}

更多:

Top-Most-MessageBox 示例

于 2017-03-23T14:54:47.790 回答