Stopping background worker

17,532

Solution 1

Same answer as Marc Gravell but you don't seem to follow.

Are you setting e.cancel = true?

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int i = 1; i <= 10; i++)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // Perform a time consuming operation and report progress.
                    System.Threading.Thread.Sleep(500);
                    worker.ReportProgress(i * 10);
                }
            }
        }

Solution 2

When you create the worker, set worker.WorkerSupportsCancellation to true. Now inside the DoWork handler, you must periodically (most commonly, at the start of some loop, etc) check for worker.CancellationPending - if it is true, set e.Cancel = true; (so that you can distinguish completion from cancellation), clean-up, and exit (return;). Now your cancel button can invoke worker.CancelAsync(); and it will act appropriately.

Solution 3

I hardly found a nice way how to cancel a Backgroundworker over a Stop Button:

My App looks like this, two buttons and one progressbar:

enter image description here

After pressed Stop Button it looks like this:

enter image description here

For the Start button click method, the code checks if the BGW is busy. If not Start the BGW:

private void btnStart_Click(object sender, EventArgs e)
    {


        //BGW
        if (!backgroundWorker1.IsBusy)
        {

            backgroundWorker1.RunWorkerAsync();

        }



    }

The stop button calls the following method, which sets a flag, CancellationPending to true:

        private void btnStop_Click(object sender, EventArgs e)
    {
        backgroundWorker1.CancelAsync();
    }

This flag can be used in the backgroundWorker1_DoWork method, which is responsible for processing high time consuming functions:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i <= 100; i++)
        {

            backgroundWorker1.ReportProgress(i);
            Thread.Sleep(100);



            if (backgroundWorker1.CancellationPending && backgroundWorker1.IsBusy)
            {
                e.Cancel = true;
                return;
            }
        }
    }

And now comes the tricky part, because before closing the extra thread, you have to check the e object in the backgroundWorker1_ProgressChanged if it is cancelled or not!!!!! OTHERWISE you will get an Error.

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        int i = 0;

        if (!e.Cancelled)
        {
            i = (int)(e.Result);
        }
        else
        {
            i = 0;
        }

        // Check to see if an error occurred in the
        // background process.
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
            return;
        }

        // Check to see if the background process was cancelled.
        if (e.Cancelled)
        {
            MessageBox.Show("Processing cancelled.");
            return;
        }

        // Everything completed normally.
        // process the response using e.Result
        MessageBox.Show("Processing is complete.");

    }

Extra information: Dont forget to set these Backgroundworker flags:

            //Set WorkerReportsProgress true - otherwise no ProgressChanged active
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = true;

If this tiny tutorial was helpful --> Thumb up

Share:
17,532
user1779064
Author by

user1779064

Updated on June 04, 2022

Comments

  • user1779064
    user1779064 almost 2 years

    My app uses background worker to go do some work inside a loop. I have it so that at each loop iteration, it checks if cancellation pending is true and if it is, breaks out the loop. All OK, my app stops processing once it is finished the current iteration of the loop. The problem is that I think the background worker is still running - if I click the button to start processing again, I get an error saying the background worker is busy.

    I was going to dispose of the worker but then it is created when the form runs and so if I dispose of it, it is not there to start doing work again. What I really want to do is tell the background worker that it is complete, if I click a 'stop processing' button, so it is ready to start processing again when I click the start button!

    I was going to try this:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
        while (!backgroundWorker1.CancellationPending) 
        {
            // Start processing in a background thread so the GUI remains responsive,
            // pass in the name of the text file produced by 
            // PFDR FilenameLogic(txtLetterType.Text); 
        } 
    }
    
    • Sergey Berezovskiy
      Sergey Berezovskiy about 11 years
      Are you waiting for RunWorkerCompleted event for enabling start processing button?
    • Balázs Szántó
      Balázs Szántó about 11 years
      "I have it so that at each loop iteration, it checks if cancellation pending is true and if it is, breaks out the loop." Did you set the DoWorkEventArgs e parametrs Cancel property to true, when cancellation pending is true? => e.Cancel = true;
  • user1779064
    user1779064 about 11 years
    So how do I periodically check the status? I was going to use this: private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { while (!backgroundWorker1.CancellationPending) { //Start processing in a background thread so the GUI remains responsive, pass in the name of the text file produced by PFDR FilenameLogic(txtLetterType.Text); } } But will it work?
  • Marc Gravell
    Marc Gravell about 11 years
    @user1779064 without a concrete example of your handler, that is hard to answer. But don't loop until it is cancelled - otherwise it will never complete normally (if you see what I mean). Usually, the worker is processing a known quantity of work - often involving some kind of for or foreach loop - the top of those is an ideal place to check for cancellation.