Automating The InvokeRequired Code Pattern


Answer :

Lee's approach can be simplified further

public static void InvokeIfRequired(this Control control, MethodInvoker action) {     // See Update 2 for edits Mike de Klerk suggests to insert here.      if (control.InvokeRequired) {         control.Invoke(action);     } else {         action();     } } 

And can be called like this

richEditControl1.InvokeIfRequired(() => {     // Do anything you want with the control here     richEditControl1.RtfText = value;     RtfHelpers.AddMissingStyles(richEditControl1); }); 

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 as ISynchronizeInvoke:

public static void InvokeIfRequired(this ISynchronizeInvoke obj,                                          MethodInvoker action) {     if (obj.InvokeRequired) {         var args = new object[0];         obj.Invoke(action, args);     } else {         action();     } } 

DonBoitnott pointed out that unlike Control the ISynchronizeInvoke interface requires an object array for the Invoke method as parameter list for the action.


UPDATE 2

Edits suggested by Mike de Klerk (see comment in 1st code snippet for insert point):

// When the form, thus the control, isn't visible yet, InvokeRequired  returns false, // resulting still in a cross-thread exception. while (!control.Visible) {     System.Threading.Thread.Sleep(50); } 

See ToolmakerSteve's comment below for concerns about this suggestion.


You could write an extension method:

public static void InvokeIfRequired(this Control c, Action<Control> action) {     if(c.InvokeRequired)     {         c.Invoke(new Action(() => action(c)));     }     else     {         action(c);     } } 

And use it like this:

object1.InvokeIfRequired(c => { c.Visible = true; }); 

EDIT: As Simpzon points out in the comments you could also change the signature to:

public static void InvokeIfRequired<T>(this T c, Action<T> action)      where T : Control 

Here's the form I've been using in all my code.

private void DoGUISwitch() {      Invoke( ( MethodInvoker ) delegate {         object1.Visible = true;         object2.Visible = false;     }); }  

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.


Comments

Popular posts from this blog

Chemistry - Bond Angles In NH3 And NCl3

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?