Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Must I Invoke() to show dialog or MessageBox from a thread?

I'm executing a code in a worker thread. Sometimes, I need to show a dialog or a Message.

I have been playing with the code and only seems to be strictly necesary to Invoke when I pass a IWin32Window to the dialog. Otherwise works fine.

My questions are two:

  1. Must I call with an Invoke?
  2. What risks I have if I show the dialog or the messagebox without Invoke?

Thanks in advance

like image 960
Daniel Peñalba Avatar asked Aug 09 '11 09:08

Daniel Peñalba


2 Answers

It is a bit of a bug in Winforms. It contains diagnostic code in the Handle property getter that verifies that the property is used in the same thread as the one that created the handle. While extremely helpful to diagnose threading bugs, that is not always appropriate. One such case is here, Windows doesn't actually require that the parent of a window is owned by the same thread.

You can work around it by pinvoking SetParent() or by temporarily disabling checking with Control.CheckForIllegalCrossThreadCalls. Or by using Control.Invoke(), the best way. Do not work around it by not specifying the owner. For lack of another window, the dialog's owner is the desktop window. It will have no Z-order relationship with the other windows that have the desktop as their owner. And that will make the dialog disappear behind another window occasionally, completely undiscoverable by the user.

There's a bigger problem though, displaying dialogs on threads is a nasty usability problem. Shoving a window into the user's face while she's working with your program is an all-around bad idea. There's no telling what will happen when she's busy clicking and typing. Her accidentally closing the dialog without even seeing it is a real danger. Don't do it.

like image 60
Hans Passant Avatar answered Oct 20 '22 19:10

Hans Passant


If you are not specifying the owner of the MessageBox it will work because it doesn't rely on the form UI thread.
I think it is safe to call it without using Invoke if you are not aware of showing as a dialog to specific form.

Edit: To test it, the following code just creating a new thread and show message box from it where at UI thread creating a second message at the same time with specifying the owner to be the form, both messages shows up without any problem:

private void button1_Click(object sender, EventArgs e)
{
    new Thread(() =>
    {
        MessageBox.Show("Hello There!");
    }) { IsBackground = true }.Start();

    Thread.Sleep(1000);

    if (MessageBox.Show(this, "Hi", "Jalal", MessageBoxButtons.YesNo) == 
        System.Windows.Forms.DialogResult.Yes)
    {
        return;
    }
}
like image 42
Jalal Said Avatar answered Oct 20 '22 19:10

Jalal Said