在Winforms中,如何使用正在运行的后台线程更新UI控件?

3

我在Winform中使用后台工作线程,在Do_Work事件中计算某些内容,同时我希望能够更新主/UI线程中的标签。如何实现?

我想要在Do_Work事件中更新我的标签...


1
请查看ReportProgress方法和ProgressChanged事件。您可以将字符串作为用户数据传递。 - H H
5个回答

10
在WinForms(WPF也是如此),UI控件只能在UI线程中更新。你应该以这种方式更新你的标签:
public void UpdateLabel(String text){
    if (label.InvokeRequired)
    {
        label.Invoke(new Action<string>(UpdateLabel), text);
        return;
    }      
    label.Text = text;
}

1

在你的Do_Work方法中,你可以使用对象的Invoke()方法在其UI线程上执行委托,例如:

this.Invoke(new Action<string>(UpdateLabel), newValue);

...然后确保在您的类中添加一个像这样的方法:

private void UpdateLabel(string value)
{
    this.lblMyLabel.Text = value;
}

0

希望这可以帮到你:

  int x = 0;
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {

        label1.Text = x.ToString();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        x++;
        //you can put any value
        backgroundWorker1.ReportProgress(0);
    }

    private void button6_Click(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

很抱歉要说,但这段代码真的没有什么帮助,甚至在“backgroundWorker1.ReportProgress(0);”这一行也会出现异常。 - yogendra
你设置了WorkerReportsProgress为true吗?如果是的话,请给我异常消息。 - Hamza_L

0
一种更通用的解决方案是使用扩展方法。这使您能够更新任何控件的Text属性。
public static class ControlExtensions
{
   public static void UpdateControlText(this Control control, string text)
   {
      if (control.InvokeRequired)
      {
         _ = control.Invoke(new Action<Control, string>(UpdateControlText), control, text);
      }

      control.Text = text;
   }

   public static void UpdateAsync(this Control control, Action<Control> action)
   {
      if(control.InvokeRequired)
      {
         _ = control.Invoke(new Action<Control, Action<Control>>(UpdateAsync), control, action);
      }

      action(control);
   }
}

你可以像这样使用方法:

TextBox1.UpdateControlText(string.Empty); // Just update the Text property

// Provide an action/callback to do whatever you want.
Label1.UpdateAsync(c => c.Text = string.Empty); 
Button1.UpdateAsync(c => c.Text == "Login" ? c.Text = "Logout" : c.Text = "Login");
Button1.UpdateAsync(c => c.Enabled == false);

0
你面临的问题是在更新用户界面(Label)时出现了跨线程异常,因为它(UI)在不同的线程(mainThread)中。你可以选择多种选项,如TPL、ThreadPool等,但实现你想要的最简单的方法是在Do_Work方法中编写一个简单的Action,如下所示: private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    x++;
    //you can put any value
    Action = act =()=>
           {
              label.Text = Convert.ToString(x);
           };
     if (label.InvokeRequired)
         label.BeginInvoke(act);
     else
          label.Invoke(act);
    backgroundWorker1.ReportProgress(0);
}

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