我过去曾使用过代理来更新当前的UI(例如文本框),其中包含正在我的线程中处理的值。我假设async
和await
为您处理此问题。
当我运行下面的代码时 - 按下按钮时,启动一个新任务,每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();
}
}
}
答案 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
为空,因此异步等待之后的代码也将在线程池线程上执行。