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
Post a Comment