从 API 的角度来看,等待任务 - 但不要阻止 UI

本文关键字:UI 任务 等待 API | 更新日期: 2023-09-27 18:30:44

在我的

一个 C# API 中运行 longProcess() 方法,在执行此操作时,我们希望等待该任务完成。但同时不想阻止 UI。我看到了很多SO线程,但对我的情况没有任何帮助。下面,方法 1 不阻止 UI,方法 2 阻止/冻结 UI。有什么想法吗?

public class MyApiManager
{
    private string _x;
    public MyApiManager(string x) 
    {
        _x = x;
    }
    public void DoProcess()
    {
        // Method 1: Does NOT block UI, but does not wait either
        Task task = Task.Factory.StartNew(() =>
        {
            Task longProcess = Task.Factory.StartNew(new Action(longProcess));
        });
        task.Wait();
        // Method 2: BLOCKS UI, also waits
        //var context = TaskScheduler.FromCurrentSynchronizationContext();
        //Task task = Task.Factory.StartNew(() =>
        //{
        //    var token = Task.Factory.CancellationToken;
        //    Task.Factory.StartNew(() =>
        //    {
        //        longProcess();
        //    }, token, TaskCreationOptions.None, context);
        //});
        //task.Wait();
    }
    private void longProcess()
    {
        // simulate long process
        Thread.Sleep(10000);
    }
}

从 API 的角度来看,等待任务 - 但不要阻止 UI

首先,您需要分离您的关注点。

MyApiManager应该对 UI 一无所知。它管理 API,根据单一责任原则,这就是它所做的一切

阅读 Stephen Toub 的 我应该为异步方法公开同步包装器吗?

UI

事件处理程序应负责确保MyApiManager不会阻止 UI。因此,将事件处理程序更改为如下所示的内容:

public async void ButtonClick_EventHandler(object o, EventArgs args)
{
    //some code
    await Task.Run(() => apiManager.DoProcess());
    //or await Task.Run(apiManager.DoProcess);
    //some more code
}

你的两种方法都过于复杂,你把任务包装在任务中,在任务中......只需使用await Task.Run,这就是您所需要的。

在方法 2 中,TaskScheduler.FromCurrentSynchronizationContext() 可能是从您的 UI 代码中调用的。因此,您可以获得 UI 调度程序上下文。

接下来,您将任务安排在 UI 线程上,longProcess() 调用处于睡眠状态,因此您在 UI 线程上休眠。正如预期的那样,UI 被阻止。