Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

CustomBackgroundWorker where the initial argument is passed to all events

4.80/5 (5 votes)
22 May 2010CPOL 17.8K  
Enables access to the original argument in all events
This came up in the forums today[^] and I figured others may find this code useful... so here it is. A simple background worker implementation (with new progress changed and run worker completed args classes) where all events have access to the initial argument.

C#
public class CustomBackgroundWorker : Component
{
    public event DoWorkEventHandler DoWork;
    public event EventHandler<CustomProgressChangedEventArgs> ProgressChanged;
    public event EventHandler<CustomRunWorkerCompletedEventArgs> RunWorkerCompleted;
    private object argument;
    private AsyncOperation asyncOperation;
    private bool cancellationPending;
    private bool isBusy;
    private bool workerReportsProgress;
    private bool workerSupportsCancellation;
    public bool CancellationPending
    {
        get { return cancellationPending; }
    }
    public bool IsBusy
    {
        get { return isBusy; }
    }
    public bool WorkerReportsProgress
    {
        get { return workerReportsProgress; }
        set { workerReportsProgress = value; }
    }
    public bool WorkerSupportsCancellation
    {
        get { return workerSupportsCancellation; }
        set { workerSupportsCancellation = value; }
    }
    private void BeginWork(object obj)
    {
        object result = null;
        Exception error = null;
        bool cancelled = false;
        try
        {
            DoWorkEventArgs doWorkEventArgs = new DoWorkEventArgs(argument);
            OnDoWork(doWorkEventArgs);
            if (doWorkEventArgs.Cancel)
                cancelled = true;
            else
                result = doWorkEventArgs.Result;
        }
        catch (Exception exception)
        {
            error = exception;
        }
        asyncOperation.PostOperationCompleted(
            new SendOrPostCallback(EndWork),
            new CustomRunWorkerCompletedEventArgs(argument, result, error, cancelled));
    }
    public void CancelAsync()
    {
        if (!WorkerSupportsCancellation)
            throw new InvalidOperationException("Worker does not support cancellation.");
        cancellationPending = true;
    }
    private void EndWork(object obj)
    {
        asyncOperation = null;
        isBusy = false;
        cancellationPending = false;
        OnRunWorkerCompleted((CustomRunWorkerCompletedEventArgs)obj);
    }
    protected virtual void OnDoWork(DoWorkEventArgs e)
    {
        DoWorkEventHandler eh = DoWork;
        if (eh != null)
            eh(this, e);
    }
    protected virtual void OnProgressChanged(CustomProgressChangedEventArgs e)
    {
        EventHandler<CustomProgressChangedEventArgs> eh = ProgressChanged;
        if (eh != null)
            eh(this, e);
    }
    protected virtual void OnRunWorkerCompleted(CustomRunWorkerCompletedEventArgs e)
    {
        EventHandler<CustomRunWorkerCompletedEventArgs> eh = RunWorkerCompleted;
        if (eh != null)
            eh(this, e);
    }
    private void ProgressReporter(object arg)
    {
        OnProgressChanged((CustomProgressChangedEventArgs)arg);
    } 
    public void ReportProgress(int percentProgress)
    {
        ReportProgress(percentProgress, null);
    }
    public void ReportProgress(int percentProgress, object userState)
    {
        if (!WorkerReportsProgress)
            throw new InvalidOperationException("Worker does not report progress.");
        CustomProgressChangedEventArgs args = new CustomProgressChangedEventArgs(
            argument, percentProgress, userState);
        if (asyncOperation != null)
            asyncOperation.Post(new SendOrPostCallback(ProgressReporter), args);
        else
            ProgressReporter(args);
    }
    public void RunWorkerAsync()
    {
        RunWorkerAsync(null);
    }
    public void RunWorkerAsync(object argument)
    {
        if (isBusy)
            throw new InvalidOperationException("Worker is busy.");
        this.argument = argument;
        isBusy = true;
        cancellationPending = false;
        asyncOperation = AsyncOperationManager.CreateOperation(null);
        new ParameterizedThreadStart(BeginWork).BeginInvoke(argument, null, null); 
    }
}


C#
public class CustomProgressChangedEventArgs : EventArgs
{
    private object argument;
    private int progressPercentage;
    private object userState;
    public CustomProgressChangedEventArgs(object argument, int progressPercentage, object userState)
    {
        this.argument = argument;
        this.progressPercentage = progressPercentage;
        this.userState = userState;
    }
    public object Argument
    {
        get { return argument; }
    }
    public int ProgressPercentage
    {
        get { return progressPercentage; }
    }
    public object UserState
    {
        get { return userState; }
    }
}


C#
public class CustomRunWorkerCompletedEventArgs : AsyncCompletedEventArgs
{
    private object argument;
    private object result;
    public CustomRunWorkerCompletedEventArgs(object argument, object result, Exception error, bool cancelled) :
        base(error, cancelled, null)
    {
        this.argument = argument;
        this.result = result;
    }
    public object Argument
    {
        get { return argument; }
    }
    public object Result
    {
        get
        {
            base.RaiseExceptionIfNecessary();
            return result;
        }
    }}

License

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