|||

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.

  • 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:


Up next Clean sources Plus If you are like me and you develop a lot of small Visual Studio Solutions that need to be checked into SVN then you’ll love this tool. I found it on SVN Externals — Share common assembly code between solutions
Latest posts Refactor react code to use state store instead of multiple useState hooks Notes on Python Threat Modelling - Using Microsoft STRIDE Model WCAG - Notes Flutter CI/CD with Azure Devops & Firebase - iOS - Part 1 Flutter CI/CD with Azure Devops & Firebase - Android - Part 2 How to samples with AWS CDK A hashicorp packer project to provision an AWS AMI with node, pm2 & mongodb Some notes on Zeebe (A scalable process orchestrator) Docker-Compose in AWS ECS with EFS volume mounts Domain Driven Design Core Principles Apple Push Notifications With Amazon SNS AWS VPC Notes Building and Deploying apps using VSTS and HockeyApp - Part 3 : Windows Phone Building and Deploying apps using VSTS and HockeyApp - Part 2 : Android Building and Deploying apps using VSTS and HockeyApp - Part 1 : iOS How I diagnosed High CPU usage using Windbg WCF service NETBIOS name resolution woes The troublesome Git-Svn Marriage GTD (Getting things done) — A simplified view Javascript Refresher Sharing common connection strings between projects A simple image carousel prototype using Asp.net webforms and SignalR Simple logging with NLog Application logger SVN Externals — Share common assembly code between solutions Simple async in .net 2.0 & Winforms Clean sources Plus Console 2 — A tabbed console window