2016-08-08 108 views
0

我是C#Task和线程的新手。C#更新UI在任务

我有象下面这样的代码: -

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(); 
           })); 

    }); 
} 

我不知道如果这个代码是否正确。我认为无论如何都会发生僵局?

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

+2

通常您只需调用Dispatcher并检查是否需要调用它的特定线程。但是我很确定你的代码不会导致死锁 –

回答

6

假设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(); 
} 

当我描述我的博客,await will automatically resume on a captured context(在这种情况下,UI上下文)。我更喜欢直接使用await而不是Dispatcher的隐式上下文:代码更短,更便于携带。

+0

UpdateSales'事件从COM对象事件处理程序中引发火灾。不知道这将是UI线程。我已经编辑了这个方法签名来正确地得到它。 –

5

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

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

所以你的代码会是这个样子:

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