Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BackgroundWorker does not stop on CancelAsync() and works only once

I've got one form called Sorter. There is the button 'jademy' on it which opens window 'Progress Window'

private void jademy_Click(object sender, EventArgs e)
{
    ProgressWindow progress = new ProgressWindow();
    progress.ShowDialog();
}

Code of 'Progress Window' form is following:

public partial class ProgressWindow : Form
{
    private BackgroundWorker backgroundWorker = new BackgroundWorker();

    public ProgressWindow()
    {
        InitializeComponent();
        stop.Visible = true;
        ok.Visible = false;
        backgroundWorker.RunWorkerAsync();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.WorkerSupportsCancellation = true;

        #region block1

        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

        #endregion
    }

    private void stop_Click(object sender, EventArgs e)
    {
        backgroundWorker.CancelAsync();
    }

    private void ok_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 1; i <= 100; i++)
        {
            Thread.Sleep(100);
            backgroundWorker.ReportProgress(i);
        }

    }

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        this.Text = "Done: " + e.ProgressPercentage.ToString() + "%";
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Cancelled == true))
        {
            MessageBox.Show("Cancelled", "Message", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
        }

        else if (!(e.Error == null))
        {
            MessageBox.Show("Error: " + e.Error.Message, "ERROR!", MessageBoxButtons.OKCancel);
        }
        else
        {
            ok.Visible = true;
            stop.Visible = false;
        }
    }
}

Now. I have three problems.

  1. Click on stop button does nothing. It seems that 'backgroundWorker.CancelAsync()' doesn't stop the process.

  2. When I close progress window and I want to run it again I have to wait some time before click on 'jademy' button. Otherwise progress window is displayed like this: enter image description here (and nothing changes) instead of this: enter image description here It looks like the program "remembers" that work was done even though it is a new instance of ProgressWindow. Notice that on the incorrect version 'OK' button is visible at once - instead of waiting for the completion of the work.

  3. I would like to clarify the code in "block 1". To be honest I don't understand it fully. Is this part really essential or not? I mean, I've found a lot of examples (also on this forum - e.g. here), where this part wasn't included and users were reporting that the solution works. In my case, without this part progress bar didn't work at all, but maybe I've done something wrong.

like image 543
Piotrek Avatar asked Dec 08 '25 22:12

Piotrek


2 Answers

  1. Calling CancelAsync stops any pending work. But if the work has already started, the method body needs to check if cancel was called. See CancelAsync

CancelAsync submits a request to terminate the pending background operation and sets the CancellationPending property to true.

When you call CancelAsync, your worker method has an opportunity to stop its execution and exit. The worker code should periodically check the CancellationPending property to see if it has been set to true.

  1. I have no idea about it. By the way the images do not work. Embed it in the question.
  2. The code assigns a method that is executed when the BackgroundWorker starts and you hook up methods to report the progress and do cleanup / updates once the background work is complete.
like image 194
Ganesh R. Avatar answered Dec 10 '25 10:12

Ganesh R.


BackgroundWorker.CancelAsync is often misunderstood. It does not stop any pending work but is merely a signal to the UI thread that the work has been canceled! It just sets the CancellationPending property, which you can poll in the DoWork regularly.

Unfortunately the MSDN example with the Thread.Sleep calls in the DoWork is a very silly one. Normally you call a blocking operation in DoWork, which is often completely UI-independent.

See my answer here for a more usable example.

like image 44
György Kőszeg Avatar answered Dec 10 '25 12:12

György Kőszeg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!