Почему 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
Блокировать окна до тех пор, пока сообщение не будет отклонено, как правило, это будет режим "модальное приложение".
Ссылочные ссылки
Предлагаемые решения работают, если вы можете получить дескриптор или ссылку на окно, над которым должен появиться диалог. Тем не менее, это не всегда возможно или просто достичь:
- окно является заставкой и не должно быть тесно связано с вашей бизнес-логикой
- окно создано другим классом или библиотекой, чем текущий
- окно находится вне вашего контроля, т.е. из сторонней (нативной) библиотеки
В таких случаях вы могли бы использовать 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
}
Для большего: