如何使用Task.Run()更改label.text

时间:2018-11-01 11:41:23

标签: c# multithreading winforms

没有任何工作await Task.Run()

private async void button2_Click(object sender, EventArgs e)
{
    await Task.Run(() => {
        monitor_r(label1);
    });
}

protected async Task monitor_r(Label L1)
{
    MessageBox.Show(L1.Name);
    L1.ForeColor = Color.Blue;
    L1.Text = "test";
}

这些命令

MessageBox.Show(L1.Name); 

L1.ForeColor = Color.Blue;  

工作正常,但

L1.Text = "test"; 

不起作用

您能帮忙,为什么不更改Label Text

3 个答案:

答案 0 :(得分:4)

尝试Control.Invoke:我们应该仅在主线程中运行Winform UI

protected async Task monitor_r(Label L1)
{
    Action action = () => 
    {
        MessageBox.Show(L1.Name);

        L1.ForeColor = Color.Blue;
        L1.Text = "test";
    };

    if (L1.InvokeRequired)
        L1.Invoke(action); // When in different thread
    else 
        action();          // When in the main thread
}

答案 1 :(得分:1)

如果处于调试模式,请查看输出窗口。它应该显示类似这样的异常消息:

  

System.Windows.Forms.dll中的System.InvalidOperationException”。

那是因为label1是从创建该线程的线程之外的线程访问的。它将导致无效的跨线程操作。

您可以通过使用Control.Invoke来解决此问题,正如Dmitry Bychenko所述。这是对Winforms Control进行线程安全调用的简单扩展。

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

示例用法

label1.TryInvoke(x => x.Text = "test"); 
label1.TryInvoke(x => x.ForeColor = Color.Blue);

this.TryInvoke(x =>
{
     label1.Text = "test";
     label1.ForeColor = Color.Blue;
});

第二,由于您monitor_r不用等待任何东西,因此建议您使用void而不是async Task

即使您在monitor_r等着您,也不需要

await Task.Run(() => {
        monitor_r(label1);
    });

..因为monitor_r本身是一项任务。因此,只需致电await monitor_r(label1);

答案 2 :(得分:0)

如果希望有一个单独的线程,可以使用BackgroundWorker尝试。如果有循环,可以实现ReportProgress。

echo "SELECT * FROM testtable" | mysql -h myserver -u root -pPASSWORD  testdb