C#- background worker's CancelAsync() not working?

Neel Bhasin picture Neel Bhasin · Aug 19, 2013 · Viewed 23.5k times · Source

I want to abort the process but not able to do so, I am using Background worker with my functions of processing.

public void Init()
{
    bw = new BackgroundWorker();
    bw.WorkerSupportsCancellation = true;
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    if (bw.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {
        e.Result = abd();
    }
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
    {
        lbltext.content="Canceled";
    }

    else
    {
        lbltext.content="Completed";
    }
}

private void btncan_Click(object sender, RoutedEventArgs e)
{
    bw.CancelAsync();
}

private void btnstart_Click(object sender, RoutedEventArgs e)
{
    bw.RunWorkerAsync();
}

I am not able to abort the process using this code. Function abd() is performing the processing part and returning the result.

Please provide me any solution.

Thanks.

Answer

Sergey Berezovskiy picture Sergey Berezovskiy · Aug 19, 2013

When you call bw.CancelAsync() you just set CancellationPending flag to true. It does not cancels something by default. You need to handle pending cancellation manually. But you can't do that with your code, because when you click button, there are three possible options:

  • Long-running abd() method finished it's work and there is nothing to cancel
  • abd() started it's work, and background worker is blocked - it's waiting for results of abd(), then it continues execution - i.e. exits if-else block and raises RunWorkerCompleted event.
  • Nearly impossible option - you will be fast as light, and you will click button before if-else block entered. Than CancellationPending will be true, and abd() will not start execution

If you want to use cancellation, then do your long-running task in a loop, and check if cancellation is pending on each step:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    List<Foo> results = new List<Foo>();

    // any loop here - foreach, while
    for(int i = 0; i < steps_count; i++)
    {    
         // check status on each step
         if (bw.CancellationPending == true) 
         {
             e.Cancel = true;
             return; // abort work, if it's cancelled
         }

         results.Add(abd()); // add part of results
    }

    e.Result = results; // return all results
}