47

Why is a C#/.NET message box not modal?

Accidentally, if the message box goes behind our main UI, then the main UI doesn't respond, until we click OK (on our message box).

Is there a workaround other than creating a custom message box?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
emeh
  • 823
  • 1
  • 7
  • 21

10 Answers10

64

You need to assign the MessageBox owner property to the main UI window (look at the 3rd constructor).

Charlie
  • 15,069
  • 3
  • 64
  • 70
12

This is a simple C# new Windows-Forms application:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string message = "You did not enter a server name. Cancel this operation?";
            string caption = "No Server Name Specified";
            MessageBoxButtons buttons = MessageBoxButtons.YesNo;
            DialogResult result;

            // Displays the MessageBox.
            result = MessageBox.Show(this, message, caption, buttons);
            if (result == DialogResult.Yes)
            {
                // Closes the parent form.
                this.Close();
            }
        }
    }
}

As Dusty states in his answer, a message box is a modal dialog. Specify the owner property. In this example, the owner is denoted by the keyword this.

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
JamesM
  • 1,048
  • 1
  • 10
  • 24
  • Just as a reminder, when going cross-thread don't forget to check `this` for `InvokeRequired`. Still, you get my +1 for demo. – Joel Oct 09 '13 at 12:36
  • 1
    @Joel, I would argue that it is bad practice to call `Invoke()` directly inside of a winforms event handler. Winforms and Designer together guarantee that events will be fired on the right GUI thread since the member controls are all instantiated on the same thread as `this`. I would even argue that, since clicking a `Button` requires its owner `Form` to have focus, specifying `owner` to `MessageBox.Show()` is unnecessary in this example. It would be necessary, say, in a `Timer.Tick` handler. Both `Invoke()` and `owner` are required when the `MessageBox.Show()` is called from another thread. – binki Aug 12 '14 at 14:38
10

To get system modal messagebox set MessageBoxOptions.DefaultDesktopOnly.

pyramidak
  • 109
  • 1
  • 3
  • 4
    This parameter leads to displaying the message box on the top of all windows on the active desktop. Meanwhile it has to have no owner. See details in MSDN - http://msdn.microsoft.com/en-us/library/system.windows.forms.messageboxoptions.aspx – Alex Klaus Sep 24 '13 at 03:54
  • 2
    To clarify, this option makes the window stay on top of all windows only if the owner is null. If the owner is non-null, it only stays on top of its owner. – Jesse Elliott Feb 03 '17 at 07:34
6

A modal pop-up is technically defined as a pop-up box that interrupts the normal flow of the application...not necessarily one that stays on the top of all other windows so the behavior you're describing is correct for a modal popup.

Modal Window

Here's a project on CodeProject that tries to mimic the "always on top" functionality for a MessageBox style Modal window:

CodeProject: TopMost MessageBox

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • 5
    His problem isn't that the dialog box gets covered by a different app. It's getting covered by the calling app. This leads to an app that cannot be used, because the dialog cannot be closed. The dialog cannot be closed, because it cannot be accessed. – Brad Bruce Jul 20 '09 at 15:27
  • Good point...I was going with this approach because it would help either situation, but if he's not concerned with other apps then setting the owner is the way to go. – Justin Niessner Jul 20 '09 at 15:55
5

You can use the owner parameter to specify a particular object, which implements the IWin32Window interface, to place the message box in front of.

A message box is a modal dialog, which means no input (keyboard or mouse click) can occur except to objects on the modal form. The program must hide or close a modal form (typically in response to some user action) before input to another form can occur.

MessageBox.Show Method

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dusty
  • 4,667
  • 3
  • 29
  • 35
2

This is working for me:

MessageBox.Show(Form.ActiveForm,"Finished processing", "Process finished", , MessageBoxButtons.OK, MessageBoxIcon.Information);

Form.ActiveForm would give you the currently active form, even if you are raising your MessageBox from any other class.

Farrukh Waheed
  • 2,163
  • 2
  • 29
  • 59
  • 1
    Does this work when no form is active (e.g., minimized)? Nope :-p. This code is identical to calling `MessageBox.Show()` without specifying any owner, in my small set of tests. – binki Aug 11 '14 at 18:53
  • Nice finding @binki. So, it work in both cases i.e. with Active Form and without any active form... :) – Farrukh Waheed Aug 12 '14 at 11:39
  • Sorry, what I’m trying to say is that specifying `Form.ActiveForm` is pointless. Let’s say your application’s window is not focused (e.g., minimized) and then your code calls `MessageBox.Show()` with no owner (which is the same as calling `MessageBox.Show(Form.ActiveForm)`). Then, when the user tries to raise your application’s main window, the user may end up raising your application’s window on top of the popped up message box. Then you get the situation described in the OP’s question where the user tries to interact with your main window but just gets "Ding" sounds from Windows ;-). – binki Aug 12 '14 at 14:29
  • This solved for me the problem that the MessageBox doesn't block the GUI of our application when it is called not from the main thread. The problem with minimized windows remains though, but it is probably not relevant for my problem. – TSchoening Nov 23 '22 at 10:09
1

Make the message box appear in the main thread, if your form has been created from it:

private bool ShowMessageBoxYesNo()
{
    if (this.InvokeRequired)
        return (bool)this.Invoke(new ShowMessageBoxYesNoDelegate(ShowMessageBoxYesNo));
    else
    {
        DialogResult res = MessageBox.Show("What ?", "Title", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
        if (res == DialogResult.Yes)
            return true;
        else
            return false;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Max
  • 19
  • 1
  • The way that `MessageBox.Show()` sets its owner (when using an overload where the owner is not specified by the caller) is to find any window in the current thread which is focused. If your `Form` is not focused (e.g., minimized) when you call `MessageBox.Show()`, your `MessageBox` will not automatically be raised when the user tries tries to raise your `Form`. Calling `Invoke()` *only* ensures that the user cannot focus your `Form`. – binki Aug 11 '14 at 18:50
0

What I usually do if I have to trigger a MessageBox from another thread (not from the main thread) is this:

  1. I create a static variable with the form instance:

    private static Form1 myform;

  2. From the thread, I invoke the operation to show the MessageBox from the main thread:

    myform.BeginInvoke((MethodInvoker)delegate() { MessageBox.Show("Process finished!", "Thread Process Information", MessageBoxButtons.OK, MessageBoxIcon.Information); });

This is just a "cookie-cutter" that I always use, and works perfectly for me.

Roberto
  • 645
  • 1
  • 8
  • 16
-2

MessageBox is a local control which is local for the server. And it does not respond until clicking OK on the message box which is displayed in the server.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
surya
  • 5
  • 1
-2
public static System.Windows.Forms.DialogResult WW_MessageBox(string Message, string Caption,
        System.Windows.Forms.MessageBoxButtons buttons, System.Windows.Forms.MessageBoxIcon icon,
        System.Windows.Forms.MessageBoxDefaultButton defaultButton)
    {
        System.Windows.Forms.MessageBox.Show(Message, Caption, buttons, icon, defaultButton,
            (System.Windows.Forms.MessageBoxOptions)8192 /*MB_TASKMODAL*/);

    }