Simple async in .net 2.0 & Winforms

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.

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:


October 2, 2011 · async · C# · c# · linqbridge · utility · Utility Classes


Previous:Clean sources Plus
Next:SVN Externals — Share common assembly code between solutions