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.