C# Windows Forms Application - Updating GUI from another thread AND class?
I've searched a ton, but I can't seem find anything relating to my specific problem.
I want to be able to update my MainUI form from another class (SocketListener) and within that I have a thread that handles the networking (clientThread). Right now I can run simple outputs from the networking thread such as writing to the debugger output and creating a MessageBox.
But what I really want to do is be able to invoke code from the clientThread that will do things on my MainUI instance. How can I do this?
Also, if anyone wants specific portions of the code then I can post it to help give you a better understanding of what I'm asking.
Best regards!
Check the InvokeRequired
of the Control
class, and if it's true, then call the Invoke
and pass in a delegate (usually an anonymous method) that does what you want to do on the client's thread.
Example:
public void DoWork(Form form)
{
if (form.InvokeRequired)
{
// We're on a thread other than the GUI thread
form.Invoke(new MethodInvoker(() => DoWork(form)));
return;
}
// Do what you need to do to the form here
form.Text = "Foo";
}
Yes, you could add a constructor to your class that takes the MainUI form as a parameter. That is the quick way to do it, but it introduces a "backward" dependency from your class to the MainUI where, in theory, no dependency is required.
As an alternative, I would suggest adding a public event to your class that the MainUI form could then subscribe to. When your class needs to update the MainUI (or controls within the MainUI), the class would simply "raise" the event. This will call the MainUI's method that it registered at the time of subscription. Since it is a method of the MainUI form already, all you have to do is update the appropriate controls on the form, making sure to take the InvokeRequired
property of each control into account.
And when doing that, here's the construct I've been using in all my code.
class NetworkEventArgs : EventArgs { /* defined class here */ }
private void NetworkEventHandler(object sender, NetworkEventArgs e)
{
Invoke( ( MethodInvoker ) delegate {
myTextBox.Text = e.Message;
}
}
I've based this on the blog entry here. I have not had this approach fail me, so I see no reason to complicate my code with a recursive check of the InvokeRequired
property.