wpf C# 在任务中更新 UI

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38829873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:53:53  来源:igfitidea点击:

C# Update UI In Task

c#wpfmultithreading

提问by Varun Jain

I am new to C#Taskand threading.

我是新手C#Task和线程。

I have a code like below:-

我有一个像下面这样的代码:-

public void UpdateSales(object sender, EventArgs args)
{
    Task.Run(() =>
    {
    // Some code Create Collection ...
    // Some code with business logic  ..


    // Below code is to update UI
    // is it safe to update UI like below 

       saleDataGrid.Dispatcher.Invoke((Action) (() =>
                                {

                                    saleDataGrid.ItemsSource = currentCollection;
                                    saleDataGrid.Items.Refresh();
                                })); 

    });
}

I am not sure if this code is correct or not. I am think in any case deadlock can occur?

我不确定此代码是否正确。我认为在任何情况下都会发生死锁?

Can you please point how can i update UI from Task? i am not using async/awaitbecause UpdateSalesis event handler from third party library.

你能指出我如何从任务更新用户界面吗?我没有使用,async/await因为UpdateSales是来自第三方库的事件处理程序。

回答by slugster

As you know, Task.Runwill execute on a threadpool thread.

如您所知,Task.Run将在线程线程上执行。

You can then use a ContinueWithwhich will run at the completion of that task - and if you choose one of the overridesthat allows you to specify a TaskScheduler then you can use TaskScheduler.FromCurrentSynchronizationContext()which will use the synchronization context that you entered the method on - if that is a UI thread (for example you are in an event handler for a UI event) then the synchronization context will be that of the UI thread.

然后,您可以使用将在该任务完成时运行的ContinueWith- 如果您选择允许您指定 TaskScheduler的覆盖之一,那么您可以使用TaskScheduler.FromCurrentSynchronizationContext()它将使用您输入的同步上下文方法 - 如果这是一个 UI 线程(例如,您在 UI 事件的事件处理程序中),那么同步上下文将是 UI 线程的同步上下文。

So your code will look something like this:

所以你的代码看起来像这样:

Task.Run(() => {
                   ...code to create collection etc...
               }
        )
        .ContinueWith(() => {
                                saleDataGrid.ItemsSource = currentCollection;
                            }
                      , TaskScheduler.FromCurrentSynchronizationContext()
                     );

回答by Stephen Cleary

Assuming that UpdateSalesis called on the UI thread, a cleaner solution would be this:

假设UpdateSales在 UI 线程上调用,一个更简洁的解决方案是这样的:

public async void UpdateSales()
{
  var collection = await Task.Run(() =>
  {
    // Some code Create Collection ...
    // Some code with business logic  ..
    return currentCollection;
  });
  saleDataGrid.ItemsSource = collection;
  saleDataGrid.Items.Refresh();
}

As I describe on my blog, the awaitwill automatically resume on a captured context(in this case, the UI context). I much prefer using the implicit context of awaitrather than Dispatcherdirectly: the code is shorter and more portable.

正如我在我的博客中所描述的,await将在捕获的上下文(在本例中为 UI 上下文)上自动恢复。我更喜欢使用隐式上下文await而不是Dispatcher直接使用:代码更短且更便携。