Automating the InvokeRequired code pattern
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
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.
If you must return a value, you can use this implementation:
private static T InvokeIfRequiredReturn<T>(this Control control, Func<T> function)
{
if (control.InvokeRequired) {
return (T)control.Invoke(function);
} else {
return function();
}
}
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 and nawfal's comments below for concerns about this suggestion.