I really like Extension methods... especially when you combine them with other good language bits to really make a difficult problem a lot easier. I think invoking on Windows Forms applications is one of those problems that is elegantly solved by some of these new features. For an in-depth background on the 'whys' and details of having to use Invoke to access GUI elements from other threads in your windows forms applications, see this article.
I have always found stopping to Invoke something to be a bit of a pain - just enough effort to derail my train of thought while working on a WinForms applications. So back in the 1.1 days, I created some helper code to try to smooth this process out a bit. On method to help out invoke was called like this:
string value = InvokeHelper.GetProperty(myTextBox, "Text");
This was an improvement on invoking without help, but essentially all I was doing was wrapping some reflection calls to coax the value from the Text property.
Now, with extention methods, lambda expressions and the ability of the compiler to infer the resolution of generic type parameters to actual types, I was able to refactor many helper methods (variations on the above for getting and setting properties, fields, calling methods, and their overloads into two methods, this is the first:
public static TResult Invoke<T, TResult>(this T controlToInvokeOn, Func<TResult> code) where T : Control
{
if (controlToInvokeOn.InvokeRequired)
{
return (TResult)controlToInvokeOn.Invoke(code);
}
else
{
return (TResult)code();
}
}
This handles the majority of cases where I wish to invoke in WinForms, it's available on all Control instanced (though I usually just invoke on the main Form instance where the controls I want to touch are) and it works without having to specifiy the return type (or where there are no return types *except in cases where the Func code isn't an expression... see below for the second method/case).
The other method is this:
public static void Invoke(this Control controlToInvokeOn, Func code)
{
if (controlToInvokeOn.InvokeRequired)
{
controlToInvokeOn.Invoke(code);
}
else
{
code();
}
}
This method has some overlap with the previous method, but its exclusive territory is cases where you pass something to the 'code' parameter that *isn't* an expression. In this overload, you are passing in a delegate defined as public delegate void Func() (which is not included in the framework, I just made it up though I could have easily used the ThreadStart delegate -- hmm, maybe I should have, oh well :)). This can be a multi-step method that includes locals etc. just like any anonymous method would. The first overload of Invoke would require you to return something at the end of your method, which I thought was ugly, so I added this second method for 'code aesthetic' purposes.
[Edit] One obvious thing I left out (you can tell I haven't blogged much recently) is is just the syntax of how this is called. Inside a Form (this), you call the method like so (in this case, setting a value on a control on the UI thread):
this.Invoke(() => progressBar1.Value = i);
This gives you easier syntax than the out of the box invoke, and only invokes if it needs to.
Returning a value from a property is pretty easy, too:
string value = this.Invoke(() => button1.Text);
The return type is resolved implicitly so you never need to cast and normally shouldn't need to explicitly supply it.
Anyway, I would like to improve this if I can. One question: is it wrong to overload the 'Invoke' method? If yes, what name should these methods have? Any other comments or questions are welcomel
Here's the code:
DemonstrateInvokeViaLambdas.zip