tags:

views:

920

answers:

4

I am trying to figure out Messagebox( ownerWindow, ... ).

Using reflector I see that the ownerWindow defaults to the ActiveWindow for the thread.

So the only time I need the ownerWindow parameter is to call Show from another thread.

However when I try this, I get a cross threading exception.

    private void button1_Click( object sender, EventArgs e ) {
        new Thread( () => MessageBox.Show( this, "Test" ) ).Start();
    }

So it looks like the only time I need the explicitly state the owner window, I cann't use it!

+2  A: 

You will have to do a BeginInvoke to marshal the call to the UI thread.

The code below is a simple example how you can do it. I haven't compiled it, so there might be errors in it, but it might give you some pointers.

private delegate void ThreadExecuteDelegate(object args);

public void StartThread
{
   Thread thread = new Thread(new ParameterizedThreadStart(ThreadExecute));
   thread.Start((IWin32Window)this);
}

private void ThreadExecute(object args)
{
    if(this.InvokeRequired)
    {
        this.BeginInvoke(new ThreadExecuteDelegate(ThreadExecute), args);
        return;
    }   

    IWin32Window window = (IWin32Window)args;
    MessageBox.Show(window, "Hello world");
}
Patrik
A: 

If you don't want to bother with explictly marshaling calls across threads, use the BackgroundWorker and ReportProgress

Scott Weinstein
A: 

You may want to take a look at Win32 Window Hierarchy and Styles to understand the difference between owner and parent windows. It's not always necessary that the ActiveWindows needs to own the messagebox, I've worked on application where the ActiveWindow was not necessarily the owner of the MessageBox.

Also according to win32 window rules control hierarchy cannot have controls created on different threads which is why you need to marshall the call to the MessageBox.Show to the parent window's thread.

Sijin
Thanks for the link, the important fact is taht window ownership is not transitive. So if you have form, spawning a form, spawning a MessageBox, you should pass in the original form as the owner of the MessageBox.
jyoung
A: 

It was the Control.Handle getter that was testing for cross threading.

Adding the following code fixes things.

   public class Win32Window :IWin32Window {
        IntPtr handle;
        public Win32Window( IWin32Window window ) {
            this.handle = window.Handle;
        }

        IntPtr IWin32Window.Handle {
            get { return handle; }
        }
    }

    private void button1_Click( object sender, EventArgs e ) {
        IWin32Window window = new Win32Window( this );
        new Thread( () => MessageBox.Show( window, "Test" ) ).Start();
    }
jyoung