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

标签 c# wpf task-parallel-library task

当在工作线程上调用的方法需要在 UI 线程上运行代码并等待它完成后再做其他事情时,可以这样完成:

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

        return res;
    }

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

一种方法如下:

public Task<int> RunOnUi(Func<int> f)
{
    var task = new Task<int>(f);
    task.Start(_scheduler);

    return task;
}

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

最佳答案

只需使用 InvokeAsync 而不是 Invoke然后返回 Task<int> DispatcherOperation<int> 里面函数返回。

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

如果您无法访问 .NET 4.5,情况会稍微复杂一些。您将需要使用 BeginInvoke 和一个 TaskCompletionSource 包装 DispaterOperation BeginInvoke返回

    public Task<int> RunOnUi(Func<int> f)
    {
        var operation = Application.Current.Dispatcher.BeginInvoke(f);
        var tcs = new TaskCompletionSource<int>();
        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;
    }

关于c# - 在 UI 线程上创建和启动任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28194943/

相关文章:

c# - 当 WritableBitmap.BackBuffer 在非 UI 线程中更新时应用程序停止响应?

c# - TransformBlock 永远不会完成

c# - 从异步 ApiController 返回即时响应

wpf - 将上下文菜单父级作为 CommandParameter 传递

c# - Azure 表存储查询性能缓慢

c# - asp.net core 中的 TempData 为空

c# - 对于一个用户,从xml字符串导入DSA key 失败。权限?安装损坏? KSP错误?

c# - C# 中的结构给出警告字段永远不会分配给,并且将始终具有其默认值 0

c# - 实例化并销毁 GameObject/ParticleSystem

c# - 当窗口大小更改时,如何在装饰器上绘制一个矩形以随其绑定(bind)到的图像元素缩放?