如何基于嵌套循环中的多个变量报告进度(对于进度条)?

时间:2016-12-14 14:35:37

标签: c# math logic progress-bar backgroundworker

我有一个BackgroundWorker和一个ProgressBar。工作时,BackgroundWorker会运行三重for循环并将进度报告给ProgressBar。

目前,正在报告的进度只是最外层循环(xProgress)的进度,它起作用,但运行不顺畅。目标是让ProgressBar还考虑内部循环的进度百分比,以便ProgressBar更顺畅,更准确地更新。

DoWork方法:

    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);
                }
            }
        }
    }

4 个答案:

答案 0 :(得分:4)

即使您事先并不了解最佳/最差情况,这仍然有效。 任何max都可以以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);
}

顺便说一句,我会将pgb.Maximum替换为1,并在OnProgressHandler中将进度乘以它。这样,线程方法根本不会触及UI元素。

答案 1 :(得分:3)

确实,您无法准确知道循环将执行多少次迭代,但您当然可以平滑进度指示器。

假设您在最坏情况下的总迭代次数是xMax * yMax * worstZMax。

worstZMax = 99,因为上限在Random.Next(minValue:int, maxValue:int)

中是唯一的

因此,最坏情况下的总迭代次数为5 * 10 * 99 = 4950

现在我们可以从这个总数开始,并在为每个y循环生成zMax后松散迭代时根据需要进行调整,我们将有效地平滑进度计算和报告。

我就是这样做的:

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);
            }
        }
    }
}

希望这有帮助!

答案 2 :(得分:1)

更新的答案:

由于内循环具有未知的迭代次数,因此您可以决定它应该前进多少步。例如10。

然后你可以这样做:

progressbarMaximum = xMax * yMax * 10

在z-loop之前,通过将zMax除以10得到zModulo。 在你的z循环中检查是否

zMax % zModulo == 0

然后递增进度条。

旧答案:

如果乘以xMax,yMax和zMax,则得到最内层循环的迭代总数。

将进度条最大值设置为该值。

在内循环增量进度条的每次迭代中。

答案 3 :(得分:0)

无法使其完全正确。可以这样想想 - 如果第一个randoms都是50并且你已经完成了2个外环的一半 - 如果其余的randoms将是50个 - 那么你已经完成了50%。如果其余的randoms将是100 - 你将只做33%。所以你不知道进度条应该有多远。

(当然随机结果通常不会那样。只是为了说明这一点。)