Click here to Skip to main content
15,884,388 members
Articles / Programming Languages / C# 4.0
Tip/Trick

CustomBackgroundWorker where the initial argument is passed to all events

Rate me:
Please Sign up or sign in to vote.
4.80/5 (5 votes)
22 May 2010CPOL 17.4K   4   6
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)


Written By
CEO Dave Meadowcroft
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionA simpler solution Pin
Mistika1222-Apr-16 10:14
Mistika1222-Apr-16 10:14 
GeneralRe: A simpler solution Pin
DaveyM693-May-16 3:59
professionalDaveyM693-May-16 3:59 
GeneralRe: A simpler solution Pin
Mistika124-May-16 8:49
Mistika124-May-16 8:49 
GeneralExcellent Pin
RugbyLeague14-Feb-10 22:20
RugbyLeague14-Feb-10 22:20 
GeneralRe: Excellent Pin
DaveyM6916-Feb-10 2:51
professionalDaveyM6916-Feb-10 2:51 
GeneralGreat Pin
Luc Pattyn12-Feb-10 12:50
sitebuilderLuc Pattyn12-Feb-10 12:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.