Ok.....I have a while loop that executes an increment on a counter for a couple thousand times. I want to be able to show the progress on the counter using a progressbar. Now, I am executing the while loop in the DoWork method of the background worker and updating the progressbar in the ProgressChanged method and when i call RunWorkerAsync then things go wrong. My problem is that the progressBar updates properly and the count increments...however my form's UI is unresponsive...it registers click events on the cancel button but it waits until the backgroundworker completes before it actually does what it has to do. If i introduce a Thread.Sleep(1) inside the while loop the form responds immediately to all events...
Can anyone help me to change my code so that my UI responds and updates itself while the backgroundworker is doing its work without the Thread.Sleep() in it
The code is something like this: NB.: the progressbar maximum is 10000
private
void startButton_Click(object sender, EventArgs e) {count = 0; backgroundWorker1.RunWorkerAsync();
}
private
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {while (count < 10000) {
if (((BackgroundWorker)sender).CancellationPending)
return;
else {
//Thread.Sleep(1);count++;
((
BackgroundWorker)sender).ReportProgress(count);}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Value = e.ProgressPercentage; }));
}
private
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs ) {Console.WriteLine("Finished");
}

BackgroundWorker problems
Tom Majarov
The above code runs fine...compiled or not
Without the Console.Writeline...its just to fast to show a cancelation....stopping a thread does not happen instantly..
t_girl
pravin333
{
this.progressBar1.Value = e.ProgressPercentage;}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){
while (count < 10000){
if (backgroundWorker1.CancellationPending) return; else{
count++;
Console.WriteLine(count);backgroundWorker1.ReportProgress(count);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e){
this.progressBar1.Value = e.ProgressPercentage;}
shirine
NintendoGameCubeRulez
Inherently, thread-to-thread marshalling is expensive and slow because it requires a CPU context switch, something that doesn't normally happen more than once every 15 to 45 msec or so. Unless you yield the quantum explicitly by blocking, sleeping or pumping messages. Although the API documentation states otherwise, I've noticed before that Sleep(0) doesn't cause a context switch on XP.
Generally, limit the rate of events in a background worker thread to avoid these issues.
Nasut Peraah
Sorry...I had left the .Sleep in my code when testing.
Replacing Sleep with Application.Doevents()....helps...but is inherently evil.
John1001
mpswaim
You don't need to use Invoke() in the ProgressChanged event handler. Both ProgressChanged and RunWorkerCompleted events are called on the thread that called BackgroundWorker.RunWorkerAsync. RunWorkerAsync uses the new .NET class AsyncOperationManager to ensure the proper thread context.
The only ill side-effect from using Invoke() would be performance.
If your background thread is running full-tilt and using most of the CPU then your GUI thread won't have CPU to refresh itself. You could try adding a Sleep(0) to see if that relinquishes enough time to the GUI thread, which is a little better than calling Sleep(1). Alternatively, you could try dropping the priority of the background worker thread. In the DoWork handler, something like System.Threading.Thread.CurrentThread.Priority = ThreadPriority.BelowNormal.
mike g.
DJE_1
Sorry, I should have noticed this sooner. You're sending progress for each incrementation of count. In this example the time span between iterations will be a fraction of a millisecond. The application message pump just can't keep up with that amount of data. The progress bar is updating because setting its Value property pushes that to the beginning of the queue leaving no time for the next item in the queue.
Depending on the size of your progress bar, there's no discernible difference between progress increments of less than about 5%. I would suggest updating progress for each 5% block of work done. In your example:
private void startButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync(0);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker backgroundWorker = sender as BackgroundWorker;
System.Diagnostics.Debug.Assert(e.Argument is Int32);
Int32 count = (Int32)e.Argument;
const int iterations = 10000000;
const int fivePercent = iterations / 20;
while (count < iterations)
{
if (backgroundWorker.CancellationPending)
{
return;
}
count++;
// report progress every 5%
if(0 == (count % fivePercent))
{
backgroundWorker.ReportProgress((count * 100) / iterations);
System.Diagnostics.Debug.WriteLine(count);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}