从 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);
}
}
首先,您需要分离您的关注点。
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 被阻止。