Thứ Sáu, 22 tháng 7, 2016

BackgroundWorker utilities helper

BackgroundWorker utilities

Manual usage:
Register events and execute DoWork()

_bgHelper.AddDoWork(OnDowork).AddRunWorkerCompleted(OnCompleted)
    .AddReportProgressChanged(OnReportProgress).SupportCancellation().DoWork();

BackgroundWorker events

private void OnDowork(object sender, DoWorkEventArgs e)
{
    if (_bgHelper.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    //TODO: Working progress
}
private void OnReportProgress(object sender, ProgressChangedEventArgs e)
{
    //TODO: Report progress on working
}
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //TODO: Working completed
}

using System;
using System.ComponentModel;
 
namespace App.Helpers
{
    /// <summary>
    /// Class BackgroundWorkerHelper.
    /// Support execute action on background thread
    /// </summary>
    public class BackgroundWorkerHelper : IDisposable
    {
        #region Private variable
        /// <summary>
        /// The _added event do work
        /// </summary>
        private bool _addedEventDoWork;
        /// <summary>
        /// The _added event run worker completed
        /// </summary>
        private bool _addedEventRunWorkerCompleted;
        /// <summary>
        /// The _worker
        /// </summary>
        private BackgroundWorker _worker;
 
        /// <summary>
        /// The _on do work event handler
        /// </summary>
        private DoWorkEventHandler _onDoWorkEventHandler;
        /// <summary>
        /// The _on report progress changed
        /// </summary>
        private ProgressChangedEventHandler _onReportProgressChanged;
        /// <summary>
        /// The _on completed event handler
        /// </summary>
        private RunWorkerCompletedEventHandler _onCompletedEventHandler;
 
        public bool CancellationPending
        {
            get
            {
                return _worker != null && _worker.CancellationPending;
            }
        }
        #endregion
 
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="BackgroundWorkerHelper"/> class.
        /// </summary>
        public BackgroundWorkerHelper() : this(new BackgroundWorker())
        {
 
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BackgroundWorkerHelper"/> class.
        /// </summary>
        /// <param name="worker">The worker.</param>
        public BackgroundWorkerHelper(BackgroundWorker worker)
        {
            _worker = worker;
        }
        #endregion
 
        #region Public functions
        /// <summary>
        /// Adds the DoWork event.
        /// </summary>
        /// <param name="onDoWorkEvent">The on do work event.</param>
        /// <returns>BackgroundWorkerHelper.</returns>
        public BackgroundWorkerHelper AddDoWork(DoWorkEventHandler onDoWorkEvent)
        {
            ReleaseEventHandler(); //Remove dupplicate event handler
            _addedEventDoWork = true;
            _onDoWorkEventHandler = onDoWorkEvent;
            _worker.DoWork += OnDoWork;
            return this;
        }
 
        /// <summary>
        /// Adds the ReportProgressChanged event.
        /// </summary>
        /// <param name="onReportProgressChanged">The on report progress changed.</param>
        /// <returns>BackgroundWorkerHelper.</returns>
        public BackgroundWorkerHelper AddReportProgressChanged(ProgressChangedEventHandler onReportProgressChanged)
        {
            _worker.WorkerReportsProgress = true;
            _onReportProgressChanged = onReportProgressChanged;
            _worker.ProgressChanged += OnProgressChanged;
            return this;
        }
 
        /// <summary>
        /// Adds the RunWorkerCompleted event.
        /// </summary>
        /// <param name="onRunWorkerCompleted">The on run worker completed.</param>
        /// <returns>BackgroundWorkerHelper.</returns>
        public BackgroundWorkerHelper AddRunWorkerCompleted(RunWorkerCompletedEventHandler onRunWorkerCompleted)
        {
            _addedEventRunWorkerCompleted = true;
            _onCompletedEventHandler = onRunWorkerCompleted;
            return this;
        }
 
        /// <summary>
        /// Supports the cancellation.
        /// </summary>
        /// <returns>BackgroundWorkerHelper.</returns>
        public BackgroundWorkerHelper SupportCancellation()
        {
            _worker.WorkerSupportsCancellation = true;
            return this;
        }
 
        /// <summary>
        /// Does the work.
        /// </summary>
        /// <param name="obj">The object.</param>
        public void DoWork(object obj = null)
        {
            if (_addedEventDoWork)
            {
                _worker.RunWorkerCompleted += OnRunWorkerCompleted;
                _worker.RunWorkerAsync(obj);
            }
        }
 
        /// <summary>
        /// Cancels this instance.
        /// </summary>
        public void Cancel()
        {
            if (_worker.WorkerSupportsCancellation)
            {
                if (_worker.IsBusy)
                {
                    _worker.CancelAsync();
                }
 
                //Release all event handler when cancel
                ReleaseEventHandler();
            }
        }
 
        /// <summary>
        /// Determines whether this instance is busy.
        /// </summary>
        /// <returns><c>true</c> if this instance is busy; otherwise, <c>false</c>.</returns>
        public bool IsBusy()
        {
            return _worker != null && _worker.IsBusy;
        }
        #endregion
 
        #region Private functions
        /// <summary>
        /// Handles the <see cref="E:DoWork" /> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="DoWorkEventArgs"/> instance containing the event data.</param>
        private void OnDoWork(object sender, DoWorkEventArgs args)
        {
            _onDoWorkEventHandler(sender, args);
        }
        /// <summary>
        /// Handles the <see cref="E:ProgressChanged" /> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="ProgressChangedEventArgs"/> instance containing the event data.</param>
        private void OnProgressChanged(object sender, ProgressChangedEventArgs args)
        {
            _onReportProgressChanged(sender, args);
        }
        /// <summary>
        /// Handles the <see cref="E:RunWorkerCompleted" /> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            if (args.Error != null)
            {
                //TODO: Write Error Log
            }
            if (_onCompletedEventHandler != null)
            {
                _onCompletedEventHandler(sender, args);
            }
            //Release all registered event handler when completed
            ReleaseEventHandler();
        }
        /// <summary>
        /// Releases the event handler.
        /// </summary>
        private void ReleaseEventHandler()
        {
            if (_addedEventDoWork)
            {
                _worker.DoWork -= OnDoWork;
                _onDoWorkEventHandler = null;
                _addedEventDoWork = false;
            }
            if (_worker.WorkerReportsProgress)
            {
                _worker.ProgressChanged -= OnProgressChanged;
                _onReportProgressChanged = null;
                _worker.WorkerReportsProgress = false;
            }
            if (_addedEventRunWorkerCompleted)
            {
                _worker.RunWorkerCompleted -= OnRunWorkerCompleted;
                _onCompletedEventHandler = null;
                _addedEventRunWorkerCompleted = false;
            }
        }
        #endregion
 
        #region Disposable
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_worker != null)
                {
                    _worker.Dispose();
                    _worker = null;
                }
            }
        }
        ~BackgroundWorkerHelper()
        {
            Dispose(false);
        }
        #endregion
    }
}