If you are like me (a lay-dev) and you swing back and forth between writing .net 4 and .net 2 apps. You are also asked to write simple winform applications from time to time, then this might help just a tad bit.
Like the rest of the world I’m in love with lambdas, extension methods, LINQ and all the cool stuff that was introduced post .net 2.0. So when i am writing in.net 2.0, this is the first pain point. I finally decided to look for a smarter way this time around & found something quite incredible.
The biggest find was Linqbridge. A simple one file library which can be downloaded from http://code.google.com/p/linqbridge/downloads/list.
Once you add this class to your solution, you have all the Linq goodness in your project. Create extension methods, lambdas, what have you.
No need for System.Core which targets .net 3.5
Having found this new power, i decided to write a small utility class of my own which would simplify calling long running / blocking methods in a asynchronous way. I knew about the backgroundworker for Winforms, but i was after the following syntax.
Execute Async > Method A which returns R > With Parameter P > Invoke Method B with R when A is done.
This is what I came up with:
/// <summary>
/// A very simple winforms extension class that lets a winform conrol execute
/// a long running / blocking operation in a async way, without the need of
/// having background worker thread and or worrying about Invalid Cross thread exception
/// </summary>
public static class WinformsAsyncHelper
{
/// <summary>
/// Executes a method asynchronously.
/// </summary>
/// <param name="sender">The control which is invoking the operation.</param>
/// <param name="lengthyMethod">The long running operation which needs to invoke asynchronously</param>
/// <param name="resultingMethod">The method that is invoked by the sender upon the completion of the blocking operation.</param>
public static void ExecuteAsync(this Control sender, Action lengthyMethod, Action resultingMethod)
{
var callback =
new AsyncCallback(asyncResult =>
{
lengthyMethod.EndInvoke(asyncResult);
sender.Invoke(resultingMethod);
});
lengthyMethod.BeginInvoke(callback, null);
}
/// <summary>
/// Executes a method asynchronously which only accepts one parameter of T and has void return type.
/// </summary>
/// <typeparam name="T">The type of the parameter in the blocking method</typeparam>
/// <param name="sender">The control which is invoking the operation.</param>
/// <param name="lengthyMethod">The long running operation which needs to invoke asynchronously</param>
/// <param name="arg">the argument of T which the long running operation needs.</param>
/// <param name="resultingMethod">The method that is invoked by the sender upon the completion of the blocking operation.</param>
public static void ExecuteAsync<T>(this Control sender, Action<T> lengthyMethod, T arg, Action resultingMethod)
{
var callback =
new AsyncCallback(asyncResult =>
{
lengthyMethod.EndInvoke(asyncResult);
sender.Invoke(resultingMethod);
});
lengthyMethod.BeginInvoke(arg, callback, null);
}
/// <summary>
/// Executes a blocking operation asynchronously (which takes a parameter) and invokes the resulting method
/// with the return value of the blocking operation.
/// </summary>
/// <typeparam name="T">The parameter type of the blocking operation</typeparam>
/// <typeparam name="TR">The result type of the blocking operation and the parameter type of the resulting method</typeparam>
/// <param name="sender">The control which is invoking the operation.</param>
/// <param name="lengthyMethod">The long running operation which needs to invoke asynchronously</param>
/// <param name="arg">The paramter for the blocking operation</param>
/// <param name="resultingMethod">The method that is invoked by the sender upon the completion of the blocking operation.</param>
public static void ExecuteAsync<T, TR>(this Control sender, Func<T, TR> lengthyMethod, T arg, Action<TR> resultingMethod)
{
var callback =
new AsyncCallback(asyncResult =>
sender.Invoke(resultingMethod, lengthyMethod.EndInvoke(asyncResult)));
lengthyMethod.BeginInvoke(arg, callback, null);
}
}
and the client code looks like:
private void button1_Click(object sender, EventArgs e)
{
this.ExecuteAsync(Operation1, ShowDone);
}
private void button2_Click(object sender, EventArgs e)
{
var someObject = new MyReferenceType {SomeValue = -1};
textBox1.Text = someObject.SomeValue.ToString();
this.ExecuteAsync(
Operation2,
someObject,
() =>
{
textBox1.Text = someObject.SomeValue.ToString();
ShowDone();
});
}
private void button3_Click(object sender, EventArgs e)
{
this.ExecuteAsync(
Operation3,
"Cheese !!",
name =>
{
textBox1.Text = name;
ShowDone();
});
}
I am sure that the WinformsAsyncHelper class can be evolved to fit more scenarios, but i suppose it provides a good starting point for doing async stuff especially if you are stuck in the dark ages.
Downloads: