Home > other >  Why can't I make BackgroundWorker() works as expected?
Why can't I make BackgroundWorker() works as expected?

Time:09-01

I'm trying to run a the following code to test BackgroundWorker, but it makes me a lot of problems:

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace BackgroundWorkingTest
{
    public partial class Form1 : Form
    {
        BackgroundWorker backgroundWorker1 = new BackgroundWorker();
        int counter;

        public Form1()
        {
            InitializeComponent();

            backgroundWorker1 = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            backgroundWorker1.DoWork  = BackgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged  = BackgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted  = BackgroundWorker1_RunWorkerCompleted;
        }

        private void StartButton_Click(object sender, EventArgs e) // Start
        {
            counter = 0;
            backgroundWorker1.RunWorkerAsync();
        }

        private void CancelButton_Click(object sender, EventArgs e) // Cancel
        {
            backgroundWorker1.CancelAsync();
            progressLabel.Text = "0";
        }

        private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // DoWork
        {
            int i;

            for (i = 0; i < 123456; i  )
            {
//              Application.DoEvents();    // This line doesn't help
//              Thread.Sleep(1);           // Enable this line solve the problem

                backgroundWorker1.ReportProgress(i   1);
                counter  ;

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

        private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) // Progress
        {
            progressLabel.Text = counter.ToString();
            progressLabel.Refresh();
        }

        private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) // Completed
        {
            if (e.Cancelled)
                MessageBox.Show("Operation Cancelled");
            else
                MessageBox.Show("Operation Completed");
        }
    }
}

1. For example, in the BackgroundWorker1_DoWork() method you can see the command:

Thread.Sleep(1);

If I disable it, then the "Cancel" button is not responding. I click it several times but it's not stopping the process and I'm not getting the "Operation Cancelled" message.

If I enable it then it works, but I don't want any Sleep(1) commands in my thread because it will just slow the process down and I don't want that.

If I enable the command:

Application.DoEvents();

it's not helping at all, and the "Cancel" button also isn't responding during the counting.

2. Another problem that I see, is that if I'm using the command:

progressLabel.Refresh();

in the ProgressChanged() event, than something very strange happens. I can see on the panel that it finished the counting, and it shows on the label: "123456". But it takes almost one minute after that until it shows me the "Operation Completed" message.

If, after the label shows "123456", I set a breakPoint in the ProgressChanged() method, then I see that it keeps entering the method with e.ProgressPercentage parameter rising all the time.

How can it be? If I see on the panel "123456", doesn't it says that the process has finished? If it did, then why doesn't it shows me the "Operation Completed" message right away?

3. If I remove the "progressLabel.Refresh()" line, then I do get the "Operation Completed" message right away after the label shows "123456", but then it doesn't shows me the counting between 0 to 123456 (as I see when the Refresh() command is enabled).

4. Another thing that I don't really understand:

When I changed the code to use an array of several BackgroundWorkers instead of just one:

BackgroundWorker[] backgroundWorker1 = new ....

with the Sleep(1) enabled, I didn't get any error message, although that all the threads set text to the same label, and write values to the same counter.

Does it makes sense? How didn't I get any runtime error for updating the same label at the same time from several BackgroundWorker threads?

Thanks very much.

CodePudding user response:

You are reporting progress too often:

for (i = 0; i < 123456; i  )
{
    backgroundWorker1.ReportProgress(i   1);

...and the message loop of the window is overflown by messages. So it can't serve the CancelButton_Click event in a timely manner.

  • Related