Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //1.12.2004 - Daniel Moth creates BackgroundWorker (http://www.danielmoth.com/Blog/)
- //4.12.2004 - DDGM: Changed text in comments, and exception messages.
- // Made RunWorkerAsync throw if no eventhandler attached
- // Added ctor to make the class work on the full framework as is
- namespace System.ComponentModel
- {
- #region EventArgs classes
- public class RunWorkerCompletedEventArgs : System.EventArgs
- {
- // This class should inherit from AsyncCompletedEventArgs but I don't see the point in the CF's case
- private readonly object mResult;
- private readonly bool mCancelled;
- private readonly System.Exception mError;
- public RunWorkerCompletedEventArgs(object aResult, System.Exception aError, bool aCancelled)
- {
- mResult = aResult;
- mError = aError;
- mCancelled = aCancelled;
- }
- public object Result
- {
- get
- {
- return mResult;
- }
- }
- public bool Cancelled
- {
- get
- {
- return mCancelled;
- }
- }
- public System.Exception Error
- {
- get
- {
- return mError;
- }
- }
- }
- public class ProgressChangedEventArgs : System.EventArgs
- {
- private readonly Int32 mProgressPercent;
- private readonly object mUserState;
- public ProgressChangedEventArgs(Int32 aProgressPercent, object aUserState)
- {
- mProgressPercent = aProgressPercent;
- mUserState = aUserState;
- }
- public Int32 ProgressPercentage
- {
- get
- {
- return mProgressPercent;
- }
- }
- public object UserState
- {
- get
- {
- return mUserState;
- }
- }
- }
- public class DoWorkEventArgs : System.ComponentModel.CancelEventArgs
- {
- private readonly object mArgument;
- private object mResult;
- public DoWorkEventArgs(object aArgument)
- {
- mArgument = aArgument;
- }
- public object Argument
- {
- get
- {
- return mArgument;
- }
- }
- public object Result
- {
- get
- {
- return mResult;
- }
- set
- {
- mResult = value;
- }
- }
- }
- #endregion
- #region Delegates for 3 events of class
- public delegate void DoWorkEventHandler(object sender, DoWorkEventArgs e);
- public delegate void ProgressChangedEventHandler(object sender, ProgressChangedEventArgs e);
- public delegate void RunWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e);
- #endregion
- #region BackgroundWorker Class
- ////// <summary>
- ////// Executes an operation on a separate thread.
- ////// </summary>
- public class BackgroundWorker : System.ComponentModel.Component
- {
- #region Public Interface
- public event DoWorkEventHandler DoWork;
- public event ProgressChangedEventHandler ProgressChanged;
- public event RunWorkerCompletedEventHandler RunWorkerCompleted;
- ////// <summary>
- ////// Initializes a new instance of the BackgroundWorker class.
- ////// </summary>
- public BackgroundWorker()
- : this(new System.Windows.Forms.Control())
- {
- // ideally we want to call Control.CreateControl()
- // without it, running on the desktop will crash (it is OK on the CF)
- // [on the full fx simply calling a control//s constructor does not create the Handle.]
- // The CreateControl method is not supported on the CF so to keep this assembly re target able
- // I have offered the alternative ctor for desktop clients
- // (where they can pass in already created controls)
- }
- ////// <summary>
- ////// Initializes a new instance of the BackgroundWorker class.
- ////// Call from the desktop code as the other ctor is not good enough
- ////// Call it passing in a created control e.g. the Form
- ////// </summary>
- public BackgroundWorker(System.Windows.Forms.Control aControl)
- : base()
- {
- mGuiMarshaller = aControl;
- }
- ////// <summary>
- ////// Gets a value indicating whether the application has requested cancellation of a background operation.
- ////// </summary>
- public bool CancellationPending
- {
- get{ return mCancelPending; }
- }
- ////// <summary>
- ////// Raises the BackgroundWorker.ProgressChanged event.
- ////// </summary>
- ////// <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param>
- public void ReportProgress(Int32 aProgressPercent)
- {
- this.ReportProgress(aProgressPercent, null);
- }
- ////// <summary>
- ////// Raises the BackgroundWorker.ProgressChanged event.
- ////// </summary>
- ////// <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param>
- ////// <param name="aUserState">The state object passed to BackgroundWorker.RunWorkerAsync(System.Object).</param>
- public void ReportProgress(Int32 aProgressPercent, object aUserState)
- {
- if (!mDoesProgress)
- {
- throw new System.InvalidOperationException("Doesn't do progress events. You must WorkerReportsProgress=True");
- }
- // Send the event to the GUI
- System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ProgressHelper), new ProgressChangedEventArgs(aProgressPercent, aUserState));
- }
- ////// <summary>
- ////// Starts execution of a background operation.
- ////// </summary>
- public void RunWorkerAsync()
- {
- this.RunWorkerAsync(null);
- }
- ////// <summary>
- ////// Starts execution of a background operation.
- ////// </summary>
- ////// <param name="aArgument"> A parameter for use by the background operation to be executed in the BackgroundWorker.DoWork event handler.</param>
- public void RunWorkerAsync(object aArgument)
- {
- if (mInUse)
- {
- throw new System.InvalidOperationException("Already in use.");
- }
- if (DoWork == null)
- {
- throw new System.InvalidOperationException("You must subscribe to the DoWork event.");
- }
- mInUse = true;
- mCancelPending = false;
- System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(DoTheRealWork), aArgument);
- }
- ////// <summary>
- ////// Requests cancellation of a pending background operation.
- ////// </summary>
- public void CancelAsync()
- {
- if (!mDoesCancel)
- {
- throw new System.InvalidOperationException("Does not support cancel. You must WorkerSupportsCancellation=True");
- }
- mCancelPending = true;
- }
- ////// <summary>
- ////// Gets or sets a value indicating whether the BackgroundWorker object can report progress updates.
- ////// </summary>
- public bool WorkerReportsProgress
- {
- get{ return mDoesProgress; }
- set{ mDoesProgress = value; }
- }
- ////// <summary>
- ////// Gets or sets a value indicating whether the BackgroundWorker object supports asynchronous cancellation.
- ////// </summary>
- public bool WorkerSupportsCancellation
- {
- get{ return mDoesCancel;}
- set{ mDoesCancel = value;}
- }
- public bool IsBusy
- {
- get{return mInUse;}
- }
- #endregion
- #region Fields
- //Ensures the component is used only once per session
- private bool mInUse;
- //Stores the cancellation request that the worker thread (user//s code) should check via CancellationPending
- private bool mCancelPending;
- //Whether the object supports canceling or not (and progress or not)
- private bool mDoesCancel;
- private bool mDoesProgress;
- //Helper objects since Control.Invoke takes no arguments
- private RunWorkerCompletedEventArgs mFinalResult;
- private ProgressChangedEventArgs mProgressArgs;
- // Helper for marshalling execution to GUI thread
- private System.Windows.Forms.Control mGuiMarshaller;
- #endregion
- #region Private Methods
- // Async(ThreadPool) called by ReportProgress for reporting progress
- private void ProgressHelper(object o)
- {
- mProgressArgs = (ProgressChangedEventArgs)o;
- mGuiMarshaller.Invoke(new System.EventHandler(TellThemOnGuiProgress));
- }
- // ControlInvoked by ProgressHelper for raising progress
- private void TellThemOnGuiProgress(object sender, System.EventArgs e)
- {
- if (ProgressChanged != null)
- ProgressChanged(this, mProgressArgs);
- }
- // Async(ThreadPool) called by RunWorkerAsync [the little engine of this class]
- private void DoTheRealWork(object o)
- {
- // declare the vars we will pass back to client on completion
- System.Exception er = null;
- bool ca = false;
- object result = null;
- // Raise the event passing the original argument and catching any exceptions
- try
- {
- DoWorkEventArgs inOut = new DoWorkEventArgs(o);
- if (DoWork != null)
- DoWork(this, inOut);
- ca = inOut.Cancel;
- result = inOut.Result;
- }
- catch (System.Exception ex)
- {
- er = ex;
- }
- // store the completed final result in a temp var
- RunWorkerCompletedEventArgs tempResult = new RunWorkerCompletedEventArgs(result, er, ca);
- // return execution to client by going async here
- System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(RealWorkHelper), tempResult);
- // prepare for next use
- mInUse = false;
- mCancelPending = false;
- }
- // Async(ThreadPool) called by DoTheRealWork [to avoid any rentrancy issues at the client end]
- private void RealWorkHelper(object o)
- {
- mFinalResult = (RunWorkerCompletedEventArgs)o;
- mGuiMarshaller.Invoke(new System.EventHandler(TellThemOnGuiCompleted));
- }
- // ControlInvoked by RealWorkHelper for raising final completed event
- private void TellThemOnGuiCompleted(object sender, System.EventArgs e)
- {
- if (RunWorkerCompleted != null)
- RunWorkerCompleted(this, mFinalResult);
- }
- #endregion
- }
- #endregion
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement