我有这段代码可以异步运行“繁重的”任务(并可能在UI上显示结果)。 据我了解,一个新的Task总是会在不同于UI的上下文中启动。 为了对此进行测试,我编写了以下代码:
private async void button2_Click(object sender, EventArgs e)
{
label2.Text = Thread.CurrentContext.ContextID.ToString();
await Task.Run(() =>
{
Thread.Sleep(2000);
label2.Text = Thread.CurrentContext.ContextID.ToString();
Thread.Sleep(2000);
});
label2.Text = Thread.CurrentContext.ContextID.ToString();
}
我认为,一个Task(在另一个上下文中运行)无法修改UI上下文中的值。这是通过任务内的label2.Text = Thread.CurrentContext.ContextID.ToString();
行来完成的。它可以完美地工作。 Thread.CurrentContext.ContextID
的任务内部和外部也相同。我还检查了当前线程(代码中未显示),它在Task中是不同的。
我认为我对任务的理解是错误的。 为什么即使在不同的线程中运行此Task,也为什么要在与UI相同的上下文中启动它?
答案 0 :(得分:0)
从一些基本测试来看,似乎没有得到跨线程异常的唯一原因是您从另一个线程放入label2
的文本与已经存在的文本匹配,因此不需要更新,就我而言,{ {1}}为0。
例如:
Thread.CurrentContext.ContextID
该代码无例外地运行,但是,如果我们更改文本:
private async void button2_Click(object sender, EventArgs e)
{
label2.Text = "Null";
await Task.Run(() =>
{
Thread.Sleep(2000);
label2.Text = SynchronizationContext.Current?.ToString() ?? "Null";
Thread.Sleep(2000);
});
label2.Text = "Done";
}
现在,我们得到了预期的交叉线程private async void button2_Click(object sender, EventArgs e)
{
label2.Text = SynchronizationContext.Current.ToString(); //WinForms Sync Context
await Task.Run(() =>
{
Thread.Sleep(2000);
label2.Text = SynchronizationContext.Current?.ToString() ?? "Null";
Thread.Sleep(2000);
});
label2.Text = "Done";
}
。因此,如果不修改UI线程组件的值,则不会发生异常,如果修改值,则会得到预期的异常。