Click here to Skip to main content
15,896,118 members
Articles / Desktop Programming / WPF

WPF: A Most Useful Threading Component

Rate me:
Please Sign up or sign in to vote.
4.97/5 (54 votes)
30 Dec 2009CPOL19 min read 122.3K   1.2K   147  
A threading component that shows failures/busy status and data.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Collections;
using System.Threading;

namespace ThreadingComponent
{
    /// <summary>
    /// A simple demo viewmodel that contains a single
    /// <see cref="ThreadableItemViewModel">ThreadableItemViewModel</see>
    /// that returns a List of <see cref="StuffData">StuffData</see>.
    /// 
    /// This class contains some TESTING/SIMULATION code that is clearly marked, and described
    /// This TESTING/SIMULATION code MUST be removed for your real production code. It is 
    /// here merely to demomstrate how the Adorners work when there is a Failure during the
    /// background threading operation
    /// </summary>
    public class Window1ViewModel : ViewModelBase
    {
        #region Data
        private ICommand runCommand;
        private ThreadableItemViewModel<List<StuffData>> threadVM =
            new ThreadableItemViewModel<List<StuffData>>();
        #endregion

        /// Pay very special attention to the code sections marked with
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        #region Constructor
        public Window1ViewModel()
        {
            //This is the threading payload delegate that will be called when the background thread
            //is run. This is the only thing that should need to change each time, apart from
            //specifiying the generic T for the ThreadableItemViewModel<T>
            Func<Dictionary<String, Object>, ThreadableItem<List<StuffData>>> taskFunc = (inputParams) =>
            {
                try
                {
                    // REGION BELOW FOR TESTING ONLY
                    // REGION BELOW FOR TESTING ONLY
                    // REGION BELOW FOR TESTING ONLY
                    // REGION BELOW FOR TESTING ONLY
                    // REGION BELOW FOR TESTING ONLY
                    //
                    // You would replace the example regions code below with something specific to your
                    // actual app domain requirements, for example here is what one of our actual
                    // production code methods (this is assuming we are using a WCF
                    // service to provide the data) may look like :
                    //
                    //try
                    //{
                    //    //Obtain a list of Clients that work in particular BusinessArea 
                    //    Service<IGateway>.Use((client) =>
                    //    {
                    //        RetrieveDataByQueryRequest request = new RetrieveDataByQueryRequest();
                    //        request.Query = new Query().SelectAll(BusinessEntityType.Client)
                    //            .Where(new Filter("BusinessAreaId", 
                    //                FieldOpeartor.Equals,(Int32)inputParams["businessArea"]);

                    //        RetrieveDataByQueryResponse response = 
                    //            (RetrieveDataByQueryResponse)client.Execute(request);

                    //        return new ThreadableItem<List<Client>>(response.Clients, String.Empty);
                    //    });
                    //}
                    ////catch WCF FaultExceptions
                    //catch (FaultException<SerializationException> sex)
                    //{
                    //    //throw actual Exception which is caught it outer catch
                    //    throw new BusinessException("A serialization issue has occurred");
                    //}
                    ////catch WCF FaultExceptions
                    //catch (FaultException<InvalidArgumentException> iaex)
                    //{
                    //    //throw actual Exception which is caught it outer catch
                    //    throw new BusinessException("One of the arguments is invalid");
                    //}

                    #region TEST EXAMPLE CODE, YOU SHOULD NOT DO THIS IN PRODUCTION CODE
                    if (ShouldFail)
                    {
                        throw new InvalidOperationException(
                            "InvalidOperationException occurred\r\n\r\n" +
                            "This Exception has been raised inside the Window1ViewModel delegate " +
                            "which is the actual payload for the ThreadableItemViewModel<T> TaskFunc delegate.\r\n\r\n" +
                            "Which is obvioulsy not what you would do in a production system.\r\n\r\n" +
                            "You would more typically catch your own business Exceptions " +
                            "(say from talking to WCF) and then rethrow them. " +
                            "This just demomstrated how all this hangs together");
                    }
                    else
                    {
                        List<StuffData> data = new List<StuffData>();
                        for (int i = 0; i < (Int32)inputParams["loopMax"]; i++)
                        {
                            data.Add(new StuffData(String.Format("The Text Is {0}",i),i));
                            Thread.Sleep(5); //simulate time going by
                        }
                        //work is done at this point, so return new ThreadableItem with the
                        //actual data in it, and no failure message
                        return new ThreadableItem<List<StuffData>>(data, String.Empty);
                    }
                    #endregion
                }
                //something went wrong so return a new ThreadableItem with the failed
                //message in it
                catch(Exception ex)
                {
                    return new ThreadableItem<List<StuffData>>(null, ex.Message);
                }
            };

            //setup Threading task function
            threadVM.TaskFunc = taskFunc;

            //setup Threading parameters
            Dictionary<String, Object> parameters = new Dictionary<String, Object>();
            parameters.Add("loopMax", 1000);
            threadVM.Parameters = parameters;


            runCommand = new SimpleCommand
            {
                CanExecuteDelegate = x => !threadVM.IsBusy,
                ExecuteDelegate = x => { threadVM.Run(); }
            };


            /// <summary>
            /// FOR TESTING ONLY
            /// FOR TESTING ONLY
            /// FOR TESTING ONLY
            /// FOR TESTING ONLY
            /// 
            /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
            /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
            /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
            /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
            /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
            /// </summary>
            shouldFailCommand = new SimpleCommand
            {
                CanExecuteDelegate = x => !threadVM.IsBusy,
                ExecuteDelegate = x => { ShouldFail = !ShouldFail; }
            };



        }
        #endregion

        #region Public Properties
        public ThreadableItemViewModel<List<StuffData>> ThreadVM
        {
            get { return threadVM; }
        }


        public ICommand RunCommand
        {
            get { return runCommand; }
        }
        #endregion



        ///This is simulation code and is only here to demonstrate how
        ///the control works with a Failure. You should remove this code
        ///within a production environment
        ///
        /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
        /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
        /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
        /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
        /// YOU NEED TO DELETE THIS IN YOUR PRODUCTION CODE
        #region SIMULATION CODE : THIS SHOULD BE REMOVED IN PRODUCTION CODE

        /// <summary>
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// </summary>
        private ICommand shouldFailCommand;

        /// <summary>
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// </summary>
        public ICommand ShouldFailCommand
        {
            get { return shouldFailCommand; }
        }


        /// <summary>
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// </summary>
        private Boolean shouldFail = false;


        /// <summary>
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// FOR TESTING ONLY
        /// </summary>
        public bool ShouldFail
        {
            get { return shouldFail; }
            set
            {
                shouldFail = value;
                NotifyPropertyChanged("ShouldFail");
            }
        }
        #endregion

    }
}

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
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions