为什么Await之后的代码不能在UI线程上运行?

时间:2016-03-24 23:04:46

标签: c# async-await

我过去曾使用过代理来更新当前的UI(例如文本框),其中包含正在我的线程中处理的值。我假设asyncawait为您处理此问题。

当我运行下面的代码时 - 按下按钮时,启动一个新任务,每100毫秒计数100个。计数应显示在UI上,但我得到一个targetInvocationException:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        textBox1.Text = "Press button";
    }

    private async void button1_Click(object sender, EventArgs e)
    {
         await Task1();
    }

    private Task Task1()
    {
        return Task.Factory.StartNew(() => CountMethod());
    }

    private void CountMethod()
    {
        for (int i = 0; i < 100; i++)
        {
            Task.Delay(100).Wait();
            //Console.WriteLine(i.ToString());
            textBox1.Text = i.ToString();
        }
    }
}

1 个答案:

答案 0 :(得分:9)

问题是您正在使用线程池线程来访问UI。您正在使用Task.Factory.StartNew方法执行此操作。

以下是解决问题的方法:

private async Task Task1()
{
    for (int i = 0; i < 100; i++)
    {
        await Task.Delay(100);

        textBox1.Text = i.ToString();
    }
}

await将捕获当前SynchronizationContext,以便在异步等待完成后,后续代码在UI线程上执行。这是正确的,因为UI线程调用await(在我的示例中)。

在当前代码中,在线程池线程上调用await。在这种情况下,当前SynchronizationContext为空,因此异步等待之后的代码也将在线程池线程上执行。