在UI线程上创建和启动任务

当一个在工作线程上调用的方法需要在UI线程上运行代码并在执行其他操作之前等待它完成时,可以这样做:

public int RunOnUi(Func f) { int res = Application.Current.Dispatcher.Invoke(f); return res; } 

但是,如果我想用任务做什么呢? 有没有办法让RunOnUi方法创建一个在UI上启动并返回它的任务,以便调用者(在工作线程上运行)可以等待它? 适合以下签名的东西: public Task StartOnUi(Func f)

一种方法如下:

 public Task RunOnUi(Func f) { var task = new Task(f); task.Start(_scheduler); return task; } 

这里,假设_schduler持有ui TaskScheduler 。 但是我不太习惯于创建“冷”任务并使用start方法来运行它们。 这是“推荐”的方式还是有更优雅的方式来做到这一点?

只需使用InvokeAsync而不是Invoke然后返回函数返回的DispatcherOperationTask

 //Coding conventions say async functions should end with the word Async. public Task RunOnUiAsync(Func f) { var dispatcherOperation = Application.Current.Dispatcher.InvokeAsync(f); return dispatcherOperation.Task; } 

如果您无法访问.NET 4.5,则会更复杂一些。 您将需要使用BeginInvokeTaskCompletionSource来包装BeginInvoke返回的DispaterOperation

  public Task RunOnUi(Func f) { var operation = Application.Current.Dispatcher.BeginInvoke(f); var tcs = new TaskCompletionSource(); operation.Aborted += (sender, args) => tcs.TrySetException(new SomeExecptionHere()); operation.Completed += (sender, args) => tcs.TrySetResult((int)operation.Result); //The operation may have already finished and this check accounts for //the race condition where neither of the events will ever be called //because the events where raised before you subscribed. var status = operation.Status; if (status == DispatcherOperationStatus.Completed) { tcs.TrySetResult((int)operation.Result); } else if (status == DispatcherOperationStatus.Aborted) { tcs.TrySetException(new SomeExecptionHere()); } return tcs.Task; }