Advertisement
Guest User

Backgroundworker for Compact Framework 3.5 - converted to C#

a guest
Dec 5th, 2013
412
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.64 KB | None | 0 0
  1. //1.12.2004 - Daniel Moth creates BackgroundWorker (http://www.danielmoth.com/Blog/)
  2. //4.12.2004 - DDGM: Changed text in comments, and exception messages.
  3. //                  Made RunWorkerAsync throw if no eventhandler attached
  4. //                  Added ctor to make the class work on the full framework as is
  5.  
  6. namespace System.ComponentModel
  7. {
  8.  
  9.    #region EventArgs classes
  10.    public class RunWorkerCompletedEventArgs : System.EventArgs
  11.    {
  12.       // This class should inherit from AsyncCompletedEventArgs but I don't see the point in the CF's case
  13.       private readonly object mResult;
  14.       private readonly bool mCancelled;
  15.       private readonly System.Exception mError;
  16.  
  17.       public RunWorkerCompletedEventArgs(object aResult, System.Exception aError, bool aCancelled)
  18.       {
  19.          mResult = aResult;
  20.          mError = aError;
  21.          mCancelled = aCancelled;
  22.       }
  23.  
  24.       public object Result
  25.       {
  26.          get
  27.          {
  28.             return mResult;
  29.          }
  30.       }
  31.  
  32.       public bool Cancelled
  33.       {
  34.          get
  35.          {
  36.             return mCancelled;
  37.          }
  38.       }
  39.  
  40.       public System.Exception Error
  41.       {
  42.          get
  43.          {
  44.             return mError;
  45.          }
  46.       }
  47.    }
  48.    public class ProgressChangedEventArgs : System.EventArgs
  49.    {
  50.       private readonly Int32 mProgressPercent;
  51.       private readonly object mUserState;
  52.       public ProgressChangedEventArgs(Int32 aProgressPercent, object aUserState)
  53.       {
  54.          mProgressPercent = aProgressPercent;
  55.          mUserState = aUserState;
  56.       }
  57.       public Int32 ProgressPercentage
  58.       {
  59.          get
  60.          {
  61.             return mProgressPercent;
  62.          }
  63.       }
  64.       public object UserState
  65.       {
  66.          get
  67.          {
  68.             return mUserState;
  69.          }
  70.       }
  71.    }
  72.    public class DoWorkEventArgs : System.ComponentModel.CancelEventArgs
  73.    {
  74.       private readonly object mArgument;
  75.       private object mResult;
  76.       public DoWorkEventArgs(object aArgument)
  77.       {
  78.          mArgument = aArgument;
  79.       }
  80.       public object Argument
  81.       {
  82.          get
  83.          {
  84.             return mArgument;
  85.          }
  86.       }
  87.       public object Result
  88.       {
  89.          get
  90.          {
  91.             return mResult;
  92.          }
  93.          set
  94.          {
  95.             mResult = value;
  96.          }
  97.       }
  98.    }
  99. #endregion
  100. #region Delegates for 3 events of class
  101.    public delegate void DoWorkEventHandler(object sender, DoWorkEventArgs e);
  102.    public delegate void ProgressChangedEventHandler(object sender, ProgressChangedEventArgs e);
  103.    public delegate void RunWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e);
  104. #endregion
  105.  
  106. #region BackgroundWorker Class
  107.    ////// <summary>
  108.    ////// Executes an operation on a separate thread.
  109.    ////// </summary>
  110.    public class BackgroundWorker : System.ComponentModel.Component
  111.    {
  112. #region Public Interface
  113.       public event DoWorkEventHandler DoWork;
  114.       public event ProgressChangedEventHandler ProgressChanged;
  115.       public event RunWorkerCompletedEventHandler RunWorkerCompleted;
  116.  
  117.       ////// <summary>
  118.       ////// Initializes a new instance of the BackgroundWorker class.
  119.       ////// </summary>
  120.       public BackgroundWorker()
  121.          : this(new System.Windows.Forms.Control())
  122.       {
  123.          // ideally we want to call Control.CreateControl()
  124.          // without it, running on the desktop will crash (it is OK on the CF)
  125.          // [on the full fx simply calling a control//s constructor does not create the Handle.]
  126.  
  127.          // The CreateControl method is not supported on the CF so to keep this assembly re target able
  128.          // I have offered the alternative ctor for desktop clients
  129.          // (where they can pass in already created controls)
  130.       }
  131.  
  132.       ////// <summary>
  133.       ////// Initializes a new instance of the BackgroundWorker class.
  134.       ////// Call from the desktop code as the other ctor is not good enough
  135.       ////// Call it passing in a created control e.g. the Form
  136.       ////// </summary>
  137.       public BackgroundWorker(System.Windows.Forms.Control aControl)
  138.          : base()
  139.       {
  140.          mGuiMarshaller = aControl;
  141.       }
  142.  
  143.       ////// <summary>
  144.       ////// Gets a value indicating whether the application has requested cancellation of a background operation.
  145.       ////// </summary>
  146.       public bool CancellationPending
  147.       {
  148.          get{ return mCancelPending; }
  149.       }
  150.  
  151.       ////// <summary>
  152.       ////// Raises the BackgroundWorker.ProgressChanged event.
  153.       ////// </summary>
  154.       ////// <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param>
  155.       public void ReportProgress(Int32 aProgressPercent)
  156.       {
  157.          this.ReportProgress(aProgressPercent, null);
  158.       }
  159.  
  160.       ////// <summary>
  161.       ////// Raises the BackgroundWorker.ProgressChanged event.
  162.       ////// </summary>
  163.       ////// <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param>
  164.       ////// <param name="aUserState">The state object passed to BackgroundWorker.RunWorkerAsync(System.Object).</param>
  165.       public void ReportProgress(Int32 aProgressPercent, object aUserState)
  166.       {
  167.          if (!mDoesProgress)
  168.          {
  169.             throw new System.InvalidOperationException("Doesn't do progress events. You must WorkerReportsProgress=True");
  170.          }
  171.          // Send the event to the GUI
  172.          System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ProgressHelper), new ProgressChangedEventArgs(aProgressPercent, aUserState));
  173.       }
  174.  
  175.       ////// <summary>
  176.       ////// Starts execution of a background operation.
  177.       ////// </summary>
  178.       public void RunWorkerAsync()
  179.       {
  180.          this.RunWorkerAsync(null);
  181.       }
  182.  
  183.       ////// <summary>
  184.       ////// Starts execution of a background operation.
  185.       ////// </summary>
  186.       ////// <param name="aArgument"> A parameter for use by the background operation to be executed in the BackgroundWorker.DoWork event handler.</param>
  187.       public void RunWorkerAsync(object aArgument)
  188.       {
  189.          if (mInUse)
  190.          {
  191.             throw new System.InvalidOperationException("Already in use.");
  192.          }
  193.          if (DoWork == null)
  194.          {
  195.             throw new System.InvalidOperationException("You must subscribe to the DoWork event.");
  196.          }
  197.          mInUse = true;
  198.          mCancelPending = false;
  199.          System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(DoTheRealWork), aArgument);
  200.       }
  201.  
  202.       ////// <summary>
  203.       ////// Requests cancellation of a pending background operation.
  204.       ////// </summary>
  205.       public void CancelAsync()
  206.       {
  207.          if (!mDoesCancel)
  208.          {
  209.             throw new System.InvalidOperationException("Does not support cancel. You must WorkerSupportsCancellation=True");
  210.          }
  211.          mCancelPending = true;
  212.       }
  213.  
  214.       ////// <summary>
  215.       ////// Gets or sets a value indicating whether the BackgroundWorker object can report progress updates.
  216.       ////// </summary>
  217.       public bool WorkerReportsProgress
  218.       {
  219.          get{ return mDoesProgress; }
  220.          set{ mDoesProgress = value; }
  221.       }
  222.  
  223.       ////// <summary>
  224.       ////// Gets or sets a value indicating whether the BackgroundWorker object supports asynchronous cancellation.
  225.       ////// </summary>
  226.       public bool WorkerSupportsCancellation
  227.       {
  228.          get{ return mDoesCancel;}
  229.          set{ mDoesCancel = value;}
  230.       }
  231.  
  232.       public bool IsBusy
  233.       {
  234.          get{return mInUse;}
  235.       }
  236. #endregion
  237.  
  238. #region Fields
  239.       //Ensures the component is used only once per session
  240.       private bool mInUse;
  241.       //Stores the cancellation request that the worker thread (user//s code) should check via CancellationPending
  242.       private bool mCancelPending;
  243.  
  244.       //Whether the object supports canceling or not (and progress or not)
  245.       private bool mDoesCancel;
  246.       private bool mDoesProgress;
  247.  
  248.       //Helper objects since Control.Invoke takes no arguments
  249.       private RunWorkerCompletedEventArgs mFinalResult;
  250.       private ProgressChangedEventArgs mProgressArgs;
  251.  
  252.       // Helper for marshalling execution to GUI thread
  253.       private System.Windows.Forms.Control mGuiMarshaller;
  254.      
  255. #endregion
  256.      
  257. #region Private Methods
  258.      
  259.       // Async(ThreadPool) called by ReportProgress for reporting progress
  260.       private void ProgressHelper(object o)
  261.       {
  262.          mProgressArgs = (ProgressChangedEventArgs)o;
  263.          mGuiMarshaller.Invoke(new System.EventHandler(TellThemOnGuiProgress));
  264.       }
  265.  
  266.       // ControlInvoked by ProgressHelper for raising progress
  267.       private void TellThemOnGuiProgress(object sender, System.EventArgs e)
  268.       {
  269.          if (ProgressChanged != null)
  270.             ProgressChanged(this, mProgressArgs);
  271.       }
  272.  
  273.       // Async(ThreadPool) called by RunWorkerAsync [the little engine of this class]
  274.       private void DoTheRealWork(object o)
  275.       {
  276.          // declare the vars we will pass back to client on completion
  277.          System.Exception er = null;
  278.          bool ca = false;
  279.          object result = null;
  280.  
  281.          // Raise the event passing the original argument and catching any exceptions
  282.          try
  283.          {
  284.             DoWorkEventArgs inOut = new DoWorkEventArgs(o);
  285.             if (DoWork != null)
  286.                DoWork(this, inOut);
  287.             ca = inOut.Cancel;
  288.             result = inOut.Result;
  289.          }
  290.          catch (System.Exception ex)
  291.          {
  292.             er = ex;
  293.          }
  294.          // store the completed final result in a temp var
  295.          RunWorkerCompletedEventArgs tempResult = new RunWorkerCompletedEventArgs(result, er, ca);
  296.  
  297.          // return execution to client by going async here
  298.          System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(RealWorkHelper), tempResult);
  299.  
  300.          // prepare for next use
  301.          mInUse = false;
  302.          mCancelPending = false;
  303.       }
  304.  
  305.       // Async(ThreadPool) called by DoTheRealWork [to avoid any rentrancy issues at the client end]
  306.       private void RealWorkHelper(object o)
  307.       {
  308.          mFinalResult = (RunWorkerCompletedEventArgs)o;
  309.          mGuiMarshaller.Invoke(new System.EventHandler(TellThemOnGuiCompleted));
  310.       }
  311.  
  312.       // ControlInvoked by RealWorkHelper for raising final completed event
  313.       private void TellThemOnGuiCompleted(object sender, System.EventArgs e)
  314.       {
  315.          if (RunWorkerCompleted != null)
  316.             RunWorkerCompleted(this, mFinalResult);
  317.       }
  318. #endregion
  319.    }
  320. #endregion
  321. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement