Почему MessageBox не TopMost?

Недавно я обнаружил, что по умолчанию 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);
}

5 ответов

Решение

Показывать 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 на передний план, когда приложение свернуто в трей

Предлагаемые решения работают, если вы можете получить дескриптор или ссылку на окно, над которым должен появиться диалог. Тем не менее, это не всегда возможно или просто достичь:

  • окно является заставкой и не должно быть тесно связано с вашей бизнес-логикой
  • окно создано другим классом или библиотекой, чем текущий
  • окно находится вне вашего контроля, т.е. из сторонней (нативной) библиотеки

В таких случаях вы могли бы использовать Win232 MessageBox API от User32.dll Также доступно более простое управляемое решение:

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

Код new Form { TopMost = true } создаст скрытую форму с MB_TOPMOST свойство, которое наследуется диалоговым окном сообщения. В результате он появится поверх всех остальных ваших окон. С помощью new Form() inline не имеет побочных эффектов, не имеет визуального вида и будет нормально уничтожаться через сборщик мусора.

Примечание: если вы не находитесь внутри формы, не забудьте про пространство имен, это System.Windows.Forms.MessageBox не System.Windows.MessageBox ! (спасибо, пользователь1).

При показе MessageBox предоставить его владельцу в качестве первого аргумента. Например, при вызове из Form вызов экземпляра:

MessageBox.Show(this, "Message");

В качестве первого аргумента укажите ссылку на это окно.

Окна сообщений (и модальные формы в целом) не отображаются поверх всех окон вашего приложения. Они появляются только сверху своего владельца. Если вы хотите, чтобы ваше окно сообщений (или другие модальные формы) находились поверх экрана-заставки, установите для их владельца экземпляр формы-заставки.

Я пытаюсь вставить более полный кусок кода, это определенно работает

    [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);
        }
    }

Ответ, приведенный выше, является, очевидно, правильным, за исключением того факта, что необходимо вызвать 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

Другие вопросы по тегам