I have a BackgroundWorker and a single ProgressBar. When working, the BackgroundWorker runs through a triple for-loop and reports progress to the ProgressBar.
Currently, the progress that is being reported is only that of the outter-most loop (xProgress), which works, but does not run smoothly. The goal is for the ProgressBar to also account for the progress percentages of the inner loops, so that the ProgressBar updates more smoothly and more accurately.
The DoWork method:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int xMax, yMax, zMax;
xMax = 10;
for (int x = 1; x <= xMax; x++)
{
yMax = 5;
for (int y = 1; y <= yMax; y++)
{
zMax = new Random().Next(50, 100);
for (int z = 1; z <= zMax; z++)
{
Thread.Sleep(5); /// The process
double xProgress = (double)x / (double)xMax;
double yProgress = (double)y / (double)yMax;
double zProgress = (double)z / (double)zMax;
/// The progress calculation:
double progressCalc = xProgress;
int progress = (int)(progressCalc * pgb.Maximum);
bgw.ReportProgress(progress);
}
}
}
}
This works even if you don't know your best/worst case in advance.
Any of the max's could be randomized in the same fashion of zMax
.
static void F()
{
var r = new Random();
int xMax = 10;
int yMax = 5;
int zMax;
for (int x = 0; x < xMax; x++)
{
double xProg = (double)x / xMax;
for (int y = 0; y < yMax; y++)
{
double yProg = (double)y / (yMax * xMax);
zMax = r.Next(50, 100);
for (int z = 0; z < zMax; z++)
{
double zProg = (double)z / (zMax * yMax * xMax);
var prog = xProg + yProg + zProg;
Console.WriteLine(prog.ToString("P"));
// bgw.ReportProgress((int)(prog * pgb.Maximum));
}
}
}
Console.WriteLine(1.ToString("P")); // Make sure to report the final 100%
// bgw.ReportProgress((int)pgb.Maximum);
}
Btw, I'd replace the pgb.Maximum
's with 1
and in the OnProgressHandler
multiply the progress by it. That way the threaded method does not touch UI elements at all.
It's true that you can't know exactly how many iterations your loops will do, but you certainly can smooth your progress indicator.
Let's assume your total iterations in the worst case is xMax * yMax * worstZMax.
worstZMax = 99 because the upper bound is exclusive in Random.Next(minValue:int, maxValue:int)
Hence the total iterations in worst case scenario will be 5 * 10 * 99 = 4950
.
Now we could start with that total and adjust it as required when we loose iterations after generating zMax for each y loop and we'll effectively smooth the progress calculation and reporting.
This is how I'd do it:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
const int xMax = 10;
const int yMax = 5;
const int worstZMax = 99; //because upper is exclusive in Random.Next(lower, upper)
var iteration = 0;
var total = xMax * yMax * worstZMax; //total number of iterations (worst case)
for (var x = 1; x <= xMax; x++)
{
for (var y = 1; y <= yMax; y++)
{
var zMax = new Random().Next(50, 100);
//get how many iterations did we miss, and adjust the total iterations
total -= worstZMax - zMax;
for (var z = 1; z <= zMax; z++)
{
iteration++; //count this iteration
Thread.Sleep(5); // The process
// The progress calculation
var progress = (double)iteration / total * pgb.Maximum;
bgw.ReportProgress((int)progress);
}
}
}
}
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With