Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用连续体链更新UI_C#_.net_Task_Ui Thread_Continuewith - Fatal编程技术网

C# 用连续体链更新UI

C# 用连续体链更新UI,c#,.net,task,ui-thread,continuewith,C#,.net,Task,Ui Thread,Continuewith,我尝试使用多个连续体更新UI。所以我希望每个ContinueWith任务都会分别更新UI,但实际上,它们会互相等待,并立即更新UI。因此,即使每个ContinueWith都按时运行,但UI只在最后一个完成时更新 Thread.Sleep在这种情况下代表工作。 答复:。博客文章的最后一部分使用了与我相同的示例 我编辑了这篇帖子,回答了我自己的问题,~并排 编辑:在Test1()中,StartNew将在线程池上运行,因为没有任何特定的TaskScheduler集。因此,“Work”将在线程池上运行,

我尝试使用多个连续体更新UI。所以我希望每个ContinueWith任务都会分别更新UI,但实际上,它们会互相等待,并立即更新UI。因此,即使每个ContinueWith都按时运行,但UI只在最后一个完成时更新

Thread.Sleep在这种情况下代表工作。

答复:。博客文章的最后一部分使用了与我相同的示例

我编辑了这篇帖子,回答了我自己的问题,~并排

编辑:在Test1()中,StartNew将在线程池上运行,因为没有任何特定的TaskScheduler集。因此,“Work”将在线程池上运行,但“More Work”和“stop”将在GUI线程上运行,因为有一个设置的上下文

经验:

编辑:但是,如果“工作”在线程池上运行,为什么结果会有延迟?因为我错了。当我第二次或第n次运行测试应用程序时,您在下面看到的只是真实的

如果运行此命令,将发生以下情况:

13:32:00 - Start
--- 4 seconds later ---
13:32:01 - Work
13:32:03 - More Work
13:32:04 - stop
如果我第一次运行调试,它看起来如下所示:

编辑:我想,如果我第一次运行Test1(),那么“Work”确实会在线程池上运行。但是第二次TaskScheduler.FromCurrentSynchronizationContext()也将应用于“工作”,因此它将在GUI线程上运行。那些线程。睡眠确实是在GUI线程上运行的,我无法移动窗体

所以我的第一个问题是,为什么UI没有单独更新?因为这是我所期望的

如果我从每个ContinueWith开始一个单独的任务,我会得到想要的结果(单独的UI更新),但这看起来是错误的/丑陋的/复杂的,我感觉我没有正确地使用ContinueWith(用于UI更新)

编辑:之所以这样做,是因为我没有对ContinueWith使用“上下文”,所以它们将在线程池上运行,而不是锁定UI。新创建的任务将在UI上运行,因为这是它们设置的上下文

结果:

13:32:00 - Start
--- 1 second later ---
13:32:01 - Work
--- 2 seconds later ---
13:32:03 - More Work
--- 1 second later ---
13:32:04 - stop

编辑:tl;dr:小心使用StartNew和TaskScheduler.FromCurrentSynchronizationContext()

正确的方法是使用async/await,它将始终确保在任务返回后,即使该任务在另一个线程上执行,上下文也会在UI线程上继续

private async Task Test1()
{

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Start");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - More Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - stop");
}

void HardWorkTakesLongTime(){
    Thread.Sleep(2000);
}


// From a button click event or something like it
btn_Click(){

    Test1();
}

正确的方法是使用async/await,它将始终确保在任务返回后,即使该任务在另一个线程上执行,上下文仍在UI线程上继续

private async Task Test1()
{

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Start");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - More Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - stop");
}

void HardWorkTakesLongTime(){
    Thread.Sleep(2000);
}


// From a button click event or something like it
btn_Click(){

    Test1();
}

无法从非UI线程更新UI。您需要在UI线程上调用调用。
thread.Sleep
在使用
Tasks
时是一个非常糟糕的选择,您应该使用
Task.Delay
instead@Enigmativity我知道这就是为什么我对每个continuewith使用TaskScheduler.FromCurrentSynchronizationContext()的原因,没有这个,由于跨线程工作,我将遇到异常。您已在UI同步上下文而不是线程池上启动任务。这将阻止UI线程,您的ContinueWith调用也将继续在UI线程上进行,有效地保持其被阻止状态。因此,您的整个管道必须在UI线程解锁之前完成。正确的方法是我的答案。请阅读。@BradGonessurfing谢谢,你把我推向了正确的方向。你不能从非UI线程更新UI。您需要在UI线程上调用调用。
thread.Sleep
在使用
Tasks
时是一个非常糟糕的选择,您应该使用
Task.Delay
instead@Enigmativity我知道这就是为什么我对每个continuewith使用TaskScheduler.FromCurrentSynchronizationContext()的原因,没有这个,由于跨线程工作,我将遇到异常。您已在UI同步上下文而不是线程池上启动任务。这将阻止UI线程,您的ContinueWith调用也将继续在UI线程上进行,有效地保持其被阻止状态。因此,您的整个管道必须在UI线程解锁之前完成。正确的方法是我的答案。请阅读。@BradGonessurfing谢谢,你把我推向了正确的方向。如果你的工作是同步的,那么你就不需要所有连续的语句了。如果是异步的,那么应该使用async/await。我犯了什么错误?关于你的第一个问题。UI会立即更新,因为您首先在另一个线程上启动任务,然后从该线程更新UI(错误),然后跳转到UI并在UI线程上完成所有剩余的工作(错误)。我已更新了答案,使其对您更为明显。如果您的工作是同步的,那么您不需要所有ContinueWith语句。如果是异步的,那么应该使用async/await。我犯了什么错误?关于你的第一个问题。UI会立即更新,因为您首先在另一个线程上启动任务,然后从该线程更新UI(错误),然后跳转到UI并在UI线程上完成所有其他工作(错误)。我已更新了答案,以便让您更清楚地看到它。
13:32:00 - Start
--- 1 second later ---
13:32:01 - Work
--- 2 seconds later ---
13:32:03 - More Work
--- 1 second later ---
13:32:04 - stop
private async Task Test1()
{

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Start");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - More Work");

    await Task.Run(HardWorkTakesLongTime);

    listBox1.Items.Add($"{DateTime.Now:HH:mm:ss} - stop");
}

void HardWorkTakesLongTime(){
    Thread.Sleep(2000);
}


// From a button click event or something like it
btn_Click(){

    Test1();
}