Click here to Skip to main content
15,892,674 members
Articles / Desktop Programming / Windows Forms

A common class for executing tasks with a responsive UI

Rate me:
Please Sign up or sign in to vote.
4.74/5 (21 votes)
24 Jan 2009CPOL1 min read 93.7K   677   81  
Execute actions while making the form wait and still be responsive to other tasks.
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace Library
{
    public interface IThreadedExecuterView
    {
        void SetWait(bool isEnabled);
        void HandleException(Exception ex);
    }

    public delegate T ThreadedExecuterDelegate<T>();

    /// <summary>
    /// Class to encapsulate frequently needed action in background thread with hourglass and disabled form,
    /// then use results frombackground thread, then do something immediately after
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ThreadedExecuter<T> : IDisposable
    {
        public ThreadedExecuter()
        {
        }

        public ThreadedExecuter(IThreadedExecuterView View)
        {
            this.View = View;
        }

        BackgroundWorker worker = null;
        IThreadedExecuterView View = null;

        //for value types use default instead of null since won't be valid when casting, will alows us to use int, etc. in addition to classes
        T actionValue = default(T);

        public ThreadedExecuter<T> Process(ThreadedExecuterDelegate<T> GetResultsAction)
        {
            View.SetWait(false);

            worker = new BackgroundWorker();

            worker.DoWork += new DoWorkEventHandler(delegate(object sender, DoWorkEventArgs e)
            {
                try
                {
                    e.Result = GetResultsAction();
                }
                catch (Exception ex)
                {
                    View.HandleException(ex);
                }
            });

            return this;
        }

        public ThreadedExecuter<T> WhenFinished(Action<T> ProcessResultsAction)
        {
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e != null && e.Result != null)
                    actionValue = (T)e.Result;

                //if any end action and want to continue, call it
                //want the results action to continue to wait until done
                //but want post action to not be within wait
                try
                {
                    ProcessResultsAction(actionValue);
                }
                finally
                {
                    //don't ever want to allow this to get an exception so we can get endinvoke exception
                    //want to make sure we stop from waiting, even on error
                    try { View.SetWait(true); }
                    catch (Exception ex) { Console.WriteLine("Error setting view wait: " + ex.ToString()); }
                }
            });

            return this;
        }

        Action FinallyDelegate = null;

        public ThreadedExecuter<T> Finally(Action FinallyDelegate)
        {
            this.FinallyDelegate = FinallyDelegate;
            return this;
        }

        public ThreadedExecuter<T> Run()
        {
            //callpost action if any
            if (FinallyDelegate != null)
            {
                worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object sender, RunWorkerCompletedEventArgs e)
                {
                    try {
                        FinallyDelegate();
                    }
                    catch (Exception ex)
                    {
                        View.HandleException(ex);
                    }
                });
            }

            worker.RunWorkerAsync();

            return this;
        }

        public void Dispose()
        {
            if (worker != null)
                worker.Dispose();
        }

    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I've been a software developer since 1996 and have enjoyed C# since 2003. I have a Bachelor's degree in Computer Science and for some reason, a Master's degree in Business Administration. I currently do software development contracting/consulting.

Comments and Discussions