Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Only 1 of 2 progress bars gets updated in BackgroundWorker

I have a simple form with 2 progressbars and 1 backgroundworker on it. I have 2 loops (one within the other) and I'd like to report back the progress of each loop once incremented. Here's the code I have:

private void buttonStart_Click(object sender, EventArgs e)
{
    workerCustomers.RunWorkerAsync();
}

private void workerCustomers_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
    progressBar2.Value = (int)e.UserState;
}

private void workerCustomers_DoWork(object sender, DoWorkEventArgs e)
{
    for (int customer = 0; customer < 50; customer++)
    {
        int customerPercentage = ++customer * 100 / 50;
        workerCustomers.ReportProgress(customerPercentage, 0);

        for (int location = 0; location < 500; location++)
        {
            int locationPercentage = ++location * 100 / 500;
            workerCustomers.ReportProgress(customerPercentage, locationPercentage);
        }

        workerCustomers.ReportProgress(customerPercentage, 0);
    }
}

When the program runs, progressbar1 gets updated just fine, but progressbar2 never moves. If I run it through the debugger, I can see the value of progressbar2 being changed, there's just no change graphically. Any ideas?

like image 821
Robert Avatar asked Oct 25 '12 10:10

Robert


1 Answers

Yes, the 2nd progress bar will fail to update if you have Aero enabled on your desktop. Which provides the animated progress bar, the one that's green by default with the traveling highlight note.

This progress bar style is special, it interpolates intermediate values and always looks smooth, even if you assign course values to the Value property. In other words, you can assign 10, 20, 30, etcetera but the bar doesn't jump. It smoothly increases the bar length.

This has side-effects. To make this animation work, the progress bar must lag. In other words, it is always showing a value that's behind the programmed value. And some time must pass for it to smoothly increase the bar length to the programmed value.

One more detail you need to know: this animation does not happen when you decrease the Value property, that immediately jumps the bar length.

So the problem is that you are updating the Value property at a very high rate, much faster than the bar can interpolate. It can never catch up. Except when you restart at 0, that immediately jumps the bar. The rate is so high that the animation can never make it to 1.

You can see this by inserting this statement inside the inner loop:

   System.Threading.Thread.Sleep(1);

Play with the argument value, you may need to increase it to 16 to see any difference. The higher you make it, the further the bar makes it by interpolation.

This is of course not a real problem, this happens because your worker isn't doing any real work. As soon as you start writing the real code this BGW is supposed to do then you'll also decrease the rate at which you call ProgressChanged.

like image 190
Hans Passant Avatar answered Sep 28 '22 07:09

Hans Passant