Why isn't MessageBox TopMost?
Asked Answered
E

5

58

I recently found out that by default MessageBoxes were not the top most form when displayed by default and I was wondering if anyone knew any circumstances when you wouldn't want the messagebox to be shown on top of other windows?

I found the issue when I started to show splash screens whilst loading an application, and it looked like my program was still running but there was a MessageBox behind the splash screen that was waiting for input.. The splash screen was shown on a different thread to the thread that called the messagebox so I imagine this is why it didn't appear above the splash; but this still doesn't explain why MessageBox doesn't have the MB_TOPMOST flag by default?

Edit

To better clarify: in the end I had to do something similar to this in the end to make a messagebox, code isn't exactly correct as wrote from memory)

[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);
}
Edrisedrock answered 19/4, 2013 at 12:53 Comment(4)
Does this answer your question? Keep Messagebox.show() on top of other application using c#Appellate
@Appellate - No, this isn't a duplicate, that question is asking how to do it, whilst this question was asking whyEdrisedrock
I can't find a perfect reference (this is close meta.https://mcmap.net/q/271327/-important-ui-features-that-are-often-left-out-closed) but I think often "why" questions cannot be answered thoroughly but instead solicit answers about how to try and solve the apparent problem, which seems to be the case here.Appellate
@Appellate - Feel free to ask a question on Meta Stack Overflow yourself if you wish but the accepted answer here gives a definitive answer as to why without any opinion necessary.Edrisedrock
T
41

To show the MessageBox on top-most of all for the application

Code

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

Reason for not being MB_TOPMOST by default

If MB_TOPMOST will be default then the MessageBox will show up in a 'system modal' mode and it will be exactly on top on that form and side effects are that the 'system modal' mode will cause the MessageBox to Block the windows until the message is dismissed normally it will be 'application modal' mode.

Reference links

  1. MSDN forum - How to display a MessageBox as topmost window
  2. SO - C# MessageBox To Front When App is Minimized To Tray
Tremblay answered 19/4, 2013 at 13:20 Comment(5)
This answer looks great! but I thought messageboxes blocked the windows anyway?Edrisedrock
From the msdn forum mentioned in the answer I found that there is something like system modal and application modal. May be I'll check for more details later on this..Tremblay
Only modal message boxes bock their forms, the 'regular' one can still persist even after you exited out of the program that spawned it.Holster
I believe that msdn page is where I got the idea from for my eventual solution, I think the point about system modal vs application modal is exactly what I was looking for thanks :D (will accept soon)Edrisedrock
As an additional note, imagine if the default were for MessageBoxs to be topmost: You are working in Application A, with Application B in the background running some operation. While you are working, Application B throws a MessageBox, which being topmost, appears over the top of Application A. Without any context, at best you might be confused, at worst, you could interpret the message in the context of Application A and click the wrong option, causing some unintended action in Application B.Phosphorism
C
94

The proposed solutions work if you can get a handle or reference to the window the dialog is supposed to appear on top of. However, this may not always be possible or easy to achieve:

  • the window is a splash screen and should not tightly coupled with your business logic
  • the window is created by another class or library than the current one
  • the window is out of your control, i.e. from a third party (native) library

In such scenarios, you could use the Win232 MessageBox API from User32.dll, but a simpler, managed solution is also available:

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

The code new Form { TopMost = true } will create a hidden form with the MB_TOPMOST property, which is inherited by the messagebox dialog window. As a result, it will appear on top of all your other windows. Using new Form() inline has no side-effects, has no visual appearance and it will be destroyed normally via the garbage collector.

Note: if you are not inside a form already, don't forget the namespace, this is System.Windows.Forms.MessageBox, not System.Windows.MessageBox! (thanks, user1).

Confounded answered 18/5, 2014 at 16:0 Comment(11)
Interesting approach, the answer chosen is done so because of the difference between application modal and system modal. Your approach I assume would still keep the messagebox application modal and would be useful in the circumstances you have outlined. +1Edrisedrock
@Sayse: indeed, it keeps the messagebox application modal. We use it a lot in business logic library methods that are allowed to open a messagebox, but it is just to cumbersome to always have to pass the current form as a parameter.Confounded
Just to clarify for others this is System.Windows.Forms.MessageBox not System.Windows.MessageBoxGillam
This is the only solution that solved my problem. Thanks Abel!Christean
Thanks this is the best solution, also for those who are getting "Cross thread Exception" using "this" should use "new Form { TopMost = true }".Calix
I found this while making an Excel AddIn, and for anyone in a similar situation where the MessageBox isn't popping up in front, adding Application.DoEvents(); before calling MessageBox.Show() fixed the problem for me. This answer also worked, but on multimonitor setups it would create the message box on the 1st monitor instead of the monitor that the Excel window is in.Enrol
MessageBox.Show(new Form { TopMost = true }, "Hello, I'm on top!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); - best for me!!Tomy
For WPF it will be MessageBox.Show(new Window(){ TopMost = true }, "Hello, I'm on top!");Alterant
In my case the problem was with MessageBox's display before the main window was shown. I took to the trick of starting the still hidden main window with TopMost = true, using MessageBox::Show(this, "message"), this referring to the main window, getting the Shown message of the main window and resetting TopMost there to false again. (C++ CLI)Collative
@PawełIwaneczko was close: new System.Windows.Window() { Topmost = true }, - no capital MIncorporating
I used messagebox in a class (without form) and it worked . thanks.Pronghorn
T
41

To show the MessageBox on top-most of all for the application

Code

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

Reason for not being MB_TOPMOST by default

If MB_TOPMOST will be default then the MessageBox will show up in a 'system modal' mode and it will be exactly on top on that form and side effects are that the 'system modal' mode will cause the MessageBox to Block the windows until the message is dismissed normally it will be 'application modal' mode.

Reference links

  1. MSDN forum - How to display a MessageBox as topmost window
  2. SO - C# MessageBox To Front When App is Minimized To Tray
Tremblay answered 19/4, 2013 at 13:20 Comment(5)
This answer looks great! but I thought messageboxes blocked the windows anyway?Edrisedrock
From the msdn forum mentioned in the answer I found that there is something like system modal and application modal. May be I'll check for more details later on this..Tremblay
Only modal message boxes bock their forms, the 'regular' one can still persist even after you exited out of the program that spawned it.Holster
I believe that msdn page is where I got the idea from for my eventual solution, I think the point about system modal vs application modal is exactly what I was looking for thanks :D (will accept soon)Edrisedrock
As an additional note, imagine if the default were for MessageBoxs to be topmost: You are working in Application A, with Application B in the background running some operation. While you are working, Application B throws a MessageBox, which being topmost, appears over the top of Application A. Without any context, at best you might be confused, at worst, you could interpret the message in the context of Application A and click the wrong option, causing some unintended action in Application B.Phosphorism
G
7

When showing MessageBox provide its owner as the first argument. For example when invoking from a Form instance call:

MessageBox.Show(this, "Message");

Provide a reference to the window owning it as the first argument.

Message boxes (and modal forms in general) do not appear on top of all windows of your application. They only appear on top of their owner. If you want your message-box (or other modal forms) be on top of your splash screen, set their owner to the splash form instance.

Gomar answered 19/4, 2013 at 13:5 Comment(2)
I don't understand your answer.. how would this ensure a messagebox is always above all other windows? or what does this achieve?Edrisedrock
It won't. It will always be on top of its owner only. If you want it to appear on top of splash screen set its owner to the splash screen instance.Gomar
S
3

The answer given above is obviously correct minus the fact that it needs to call System.iDisposable.Dispose on the object new Form.

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
}

For more:

Top-Most-MessageBox Examples

Sachikosachs answered 23/3, 2017 at 14:54 Comment(0)
S
3

I try to paste a more complete code piece, it's definitely working

    [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);
        }
    }
Stook answered 28/12, 2017 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.