标签文本直到整个循环完成后才会更新

4
我有一个Winform程序,当用户点击按钮时进行一些计算,然后调用picturebox paint事件来根据计算结果绘制新的BMP。这很好地实现了。
现在我想做100次这样的操作,每次刷新picturebox时,我希望通过更新标签上的文本来显示当前迭代的情况,如下所示:
 private void button2_Click(object sender, EventArgs e)
        {

        for (int iterations = 1; iterations <= 100; iterations++)
        {
            // do some calculations to change the cellmap parameters
            cellMap.Calculate();

            // Refresh picturebox1
            pictureBox1.Invalidate();
            pictureBox1.Update();

            // Update label with the current iteration number
            label1.Text = iterations.ToString();
        }
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {

        Bitmap bmp = new Bitmap(cellMap.Dimensions.Width, cellMap.Dimensions.Height);
        Graphics gBmp = Graphics.FromImage(bmp);

        int rectWidth = scaleFactor;
        int rectHeight = scaleFactor;

         // Create solid brushes
        Brush blueBrush = new SolidBrush(Color.Blue);
        Brush greenBrush = new SolidBrush(Color.Green);
        Brush transparentBrush = new SolidBrush(Color.Transparent);

        Graphics g = e.Graphics;

        for (int i = 0; i < cellMap.Dimensions.Width; i++)
        {
                for (int j = 0; j < cellMap.Dimensions.Height; j++)
                {
                    // retrieve the rectangle and draw it
                    Brush whichBrush;

                    if (cellMap.GetCell(i, j).CurrentState == CellState.State1)
                    {
                        whichBrush = blueBrush;
                    }
                    else if (cellMap.GetCell(i, j).CurrentState == CellState.State2)
                    {
                        whichBrush = greenBrush;
                    }
                    else
                    {
                        whichBrush = transparentBrush;
                    }

                    // draw rectangle to bmp
                    gBmp.FillRectangle(whichBrush, i, j, 1f, 1f);
                }
         }

         g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
         g.DrawImage(bmp, 0, 0, pictureBox1.Width, pictureBox1.Height);
    }

我遇到的问题是标签文本只有在最后一个picturebox更新完成后才显示出来。实际上,它不能显示从1到99。我可以看到每次刷新后图片框都会更新,因为BMP随着每次迭代而改变。你有什么想法吗?

你尝试过在文本更改后调用label1.Invalidate();和/或label1.Update();吗? - horgh
没有,但是加上这两个语句后,它开始工作了。不过我不明白为什么? - deutschZuid
尝试阅读此Control.Update Method - horgh
虽然在循环期间强制更新可能会阻塞UI线程,但最好一开始就不要阻塞UI线程。请参见重复项以解决此问题的非欺骗方式(而不是下面两个答案中看到的绝对欺骗方式)。 - Peter Duniho
2个回答

10
// Code fragement...
// 5 cent solution, add Invalidate/Update
label1.Text = iterations.ToString();
label1.Invalidate();
label1.Update();

2
我不知道为什么这个答案会得到赞。正确的答案是使用 awaitasync - Icemanind
label1.Update() 对我来说有效。我有一个事件处理程序,在事件内部我改变了标签的文本,但在更改标签的Text属性后需要Update()。谢谢。 - James K

4
回答你关于为什么要这么做的问题:Windows Forms程序在单个线程中运行 - UI线程。这意味着它必须按顺序执行代码,以便在切换回UI代码之前完成函数。换句话说,在完成函数之后才能更新图片,因此如果您更新了100次图片,只有最后一次会得到更新。使用Invalidate/Update代码告诉编译器“暂停”函数的执行,并强制它更新UI而不是等到函数结束。希望这可以帮助你!

1
请注意,强制更新用户界面需要很长时间(相对而言)。一定要对您的代码进行分析,确保您不会花费大部分时间来实际更新UI,而不是进行某些计算。 - Maxter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接