Search code examples
c#backgroundworkerdoevents

C# BackgroundWorker - how should i get rid of DoEvents


I'm trying to figure out the best way to handle a backgroundworker that is triggered off radio button clicks. I created a very simple form with 3 radio buttons and a label. Each of the radio buttons share the same event radioButton_CheckedChanged. If the event completes then I update the label to "Complete". If you click another radio button before the event completes then update label to Cancelled. Below is the code i have written in this quick example. Although the application tends to run as expected my concern is the use of Application.DoEvents. What are my alternatives to this. For obvious reasons i can't sleep while IsBusy. Am I going about this all wrong or is there a better way to do this? Thanks, poco

private void radioButton_CheckedChanged(object sender, EventArgs e)
{
  RadioButton rb = sender as RadioButton;
            if (rb.Checked)
            {
                if (backgroundWorker1.IsBusy)
                {
                    backgroundWorker1.CancelAsync();
                    while (backgroundWorker1.IsBusy)
                        Application.DoEvents();
                }

                backgroundWorker1.RunWorkerAsync();
            }
        }

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = 0; i < 100 && !worker.CancellationPending; ++i)
                Thread.Sleep(1);

            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
                label1.Text = "Canceled";
            else
                label1.Text = "Complete";
        }

Solution

  • You should move the code that must run when the BackgroundWorker completes into the RunWorkerCompleted hander. In pseudo-code:

    private void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        // ...
    
        if (backgroundWorker1.IsBusy)
        {
            backgroundWorker1.CancelAsync();
            addJobToQueue();   // Don't wait here, just store what needs to be executed.
        } else {
            backgroundWorker1.RunWorkerAsync();
        } 
    }
    
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled) {
            label1.Text = "Canceled";
        }
        else {
            label1.Text = "Complete";
        }
    
        // We've finished! See if there is more to do...
        if (thereIsAnotherJobInTheQueue())
        {
             startAnotherBackgroundWorkerTask();
        }
    }