I have a main UI thread which runs the application and creates the main window form (let's call it W
). I have also a secondary thread that I spin up and which creates a dialog box (let's call it B
).
I want to set the owner of the dialog B
to be the main window W
. The setting of B
s owner happens on the thread that created B
. Basically:
b.Owner = w;
but this throws a cross-thread exception telling me that I am tryng to access the W
object from the wrong thread.
So I tried to execute the code on the main UI thread, by using a Control.Invoke
on W
. But then, I get the same error telling me that I am trying to access B
from the wrong thread:
System.InvalidOperationException was unhandled by user code
Message=Cross-thread operation not valid: Control 'B' accessed from a
thread other than the thread it was created on.
Source=System.Windows.Forms
How am I supposed to do it right?
It's a bit of a bug in Winforms, Windows actually supports making the owner a window that was created on another thread. There's a way to disable that check, something you should never do. Except when you have to I suppose:
private void button1_Click(object sender, EventArgs e) {
var t = new Thread(() => {
Control.CheckForIllegalCrossThreadCalls = false;
var frm = new Form2();
frm.Show(this);
Control.CheckForIllegalCrossThreadCalls = true;
Application.Run(frm);
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
I do not know if this is 100% safe, there could be a Winforms interaction that screws things up. You are in untested waters here, infested with threading sharks.
B
needs to be created on the UI thread.
You can still interact with B
from the secondary thread by using Control.Invoke
.
If you're actually running two message loops on different threads, then there's no way to do what you're after. If you want W
to own B
, you're going to have to create B
on the main thread and Invoke
all of your interaction with B
from the second thread.