从C#WinForm应用程序中的循环更改标签背景颜色

时间:2017-10-10 08:37:27

标签: c# winforms

我的应用中有一系列标签 -

    Label[] labels = new Label[8];      

我想按顺序更改循环内的那些背景颜色

    private void btnPrepare_Click(object sender, EventArgs e)
    {
        Application.DoEvents();
        for (int i = 0; i < 8; i++)
        {
           labels[i].BackColor = System.Drawing.Color.Red;
           System.Threading.Thread.Sleep(2000);
        }
    }

但所有变化都是一起出现的,而不是按顺序出现。

任何帮助?

2 个答案:

答案 0 :(得分:6)

这样(快速修正):

private void btnPrepare_Click(object sender, EventArgs e) { 
  //DONE: foreach - no magic numbers (8)
  foreach (var lbl in labels) {
    lbl.BackColor = System.Drawing.Color.Red;
    lbl.Update(); // <- Update == force label repainting

    System.Threading.Thread.Sleep(2000);
  }
}

Application.DoEvents() evil :它会翻译所有事件,例如,表格关闭,当你想要时画

更好的方法是使用Task代替Thread

// async: we're going to put await in the method
private async void btnPrepare_Click(object sender, EventArgs e) { 
  //DONE: foreach - no magic numbers (8)
  foreach (var lbl in labels) {
    lbl.BackColor = System.Drawing.Color.Red;

    // await: No need in force repainting, messages translating etc.
    await Task.Delay(2000);
  }
}

答案 1 :(得分:1)

使用Control.Update()方法,这将使控件重绘其客户区域内的无效区域。

有两种方法可以重新绘制表单及其内容:

  1. 您可以使用Invalidate()方法使用Update()方法的其中一个重载。

  2. 您可以调用Refresh()方法,该方法强制控件重绘自身及其所有子项。这相当于将Invalidate()方法设置为true并将其与Update()一起使用。

  3. Invalidate()方法控制绘制或重新绘制的内容。 Update()方法控制绘画或重新绘制的时间。如果您同时使用Invalidate()Update()方法而不是调用Refresh(),那么重新绘制的内容取决于您使用的Invalidate()超载量。 Update()方法仅强制控件立即绘制,但Invalidate()方法控制调用Update()方法时绘制的内容。

    1)

    private void btnPrepare_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 8; i++)
        {
           labels[i].BackColor = System.Drawing.Color.Red;
           labels[i].Update();
           System.Threading.Thread.Sleep(2000);
        }
    }
    

    2)

    private void btnPrepare_Click(object sender, EventArgs e)
    {   
        for (int i = 0; i < 8; i++)
        {
            labels[i].BackColor = System.Drawing.Color.Red;
            labels[i].Refresh();
            System.Threading.Thread.Sleep(2000);
        }
    }
    

    如果您使用Application.DoEvents()方法(不太可能),它将处理当前在邮件队列中的所有Windows messages

    运行Windows窗体应用程序时,它会创建新窗体,然后等待事件处理。每次表单处理事件时,它都会处理与该事件相关的所有代码。所有其他事件在队列中等待。当您的代码处理事件时,您的应用程序不会响应。例如,如果在顶部拖动另一个窗口,窗口不会重新绘制。

    如果您在代码中调用DoEvents(),您的应用程序可以处理其他事件。在您的示例中,将DoEvents()添加到您的代码中,以便在另一次迭代到来时重新绘制表单。如果从代码中删除DoEvents(),则表单将在循环结束前重新显示。

    但是,与Refresh()Update()方法不同,它会处理所有事件(甚至是不必要的事件)。

    作为补充 - 我想添加this answer,简要(尽可能)说明为什么DoEvents() 危险 供使用。