I have become painfully aware of just how often one needs to write the following code pattern in event-driven GUI code, where
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
becomes:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
This is an awkward pattern in C#, both to remember, and to type. Has anyone come up with some sort of shortcut or construct that automates this to a degree? It'd be cool if there was a way to attach a function to objects that does this check without having to go through all this extra work, like a object1.InvokeIfNecessary.visible = true
type shortcut.
Previous answers have discussed the impracticality of just calling Invoke() every time, and even then the Invoke() syntax is both inefficient and still awkward to deal with.
So, has anyone figured out any shortcuts?
You could write an extension method:
And use it like this:
EDIT: As Simpzon points out in the comments you could also change the signature to:
Lee's approach can be simplified further
And can be called like this
There is no need to pass the control as parameter to the delegate. C# automatically creates a closure.
UPDATE:
According to several other posters
Control
can be generalized asISynchronizeInvoke
:DonBoitnott pointed out that unlike
Control
theISynchronizeInvoke
interface requires an object array for theInvoke
method as parameter list for theaction
.UPDATE 2
Edits suggested by Mike de Klerk (see comment in 1st code snippet for insert point):
See ToolmakerSteve's comment below for concerns about this suggestion.
You should never be writing code that looks like this:
If you do have code that looks like this then your application is not thread-safe. It means that you have code which is already calling DoGUISwitch() from a different thread. It's too late to be checking to see if it's in a different thread. InvokeRequire must be called BEFORE you make a call to DoGUISwitch. You should not access any method or property from a different thread.
Reference: Control.InvokeRequired Property where you can read the following:
In a single CPU architecture there's no problem, but in a multi-CPU architecture you can cause part of the UI thread to be assigned to the processor where the calling code was running...and if that processor is different from where the UI thread was running then when the calling thread ends Windows will think that the UI thread has ended and will kill the application process i.e. your application will exit without error.
Create a ThreadSafeInvoke.snippet file, and then you can just select the update statements, right click and select 'Surround With...' or Ctrl-K+S:
Here's an improved/combined version of Lee's, Oliver's and Stephan's answers.
The template allows for flexible and cast-less code which is much more readable while the dedicated delegate provides efficiency.
Here's the form I've been using in all my code.
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 check of the
InvokeRequired
property.Hope this helps.