从UI上下文开始的任务

时间:2019-03-20 16:12:53

标签: c# winforms async-await

我有这段代码可以异步运行“繁重的”任务(并可能在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相同的上下文中启动它?

1 个答案:

答案 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线程组件的值,则不会发生异常,如果修改值,则会得到预期的异常。