async /await for wpf applicationlication中的方法
本文关键字:方法 applicationlication wpf await for async | 更新日期: 2023-09-27 18:35:40
我有这样的问题。例如,我使用 mvvm 模式创建动态自定义用户控件。所以我发送了一个命令来创建用户控件。所以创造看起来像
private async Task<bool> OnAddUserControl1(List<ALV_VM_ADWERT> control)
{
try
{
_cancellationTokenSource = new CancellationTokenSource();
var userControl = _userControlsContainer.CreateUserControl1(control);
var task1 = Task.Factory.StartNew(() =>
{
userControl.ViewModel.InOperationEvent += OnUsercontrolInOperationChanged;
userControl.ViewModel.ValueTypeChangedEvent += OnValueTypeChanged;
userControl.ViewModel.SetExpandableName += OnSetExpandableName;
}, _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext());
var task2 = Task.Factory.StartNew(() => FinalCreatingStep(userControl, control[0].RAUMNAME.Trim()), _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext());
await Task.WhenAll(task1, task2);
return true;
}
catch (Exception)
{
return false;
}
}
我的问题是 - 创建子任务是否有意义,或者没有子任务的代码更好?如果答案是肯定的,那么我应该让所有方法异步吗?如果不是,我不应该使用什么方法进行异步?
这些事件订阅真的需要异步吗?您可能过于努力地使用异步代码。
用户控件构造函数通常是最耗时的部分,必须在 UI 线程上完成。通常,仅当涉及某种形式的 IO 或处理时,才需要异步操作;
- 读取文件
- 写入文件
- 处理大型数据集
- 跨越进程边界与服务器或连接设备通信
简而言之,异步任务在这里可能是矫枉过正的。
创建子任务是否有意义,或者最好有没有子任务的代码?
这取决于您的要求。如果您的 UI 将长时间阻塞(冻结),则必须创建一个子任务,否则不会!
如果答案是肯定的,那么我应该让所有方法异步吗?如果不是,我不应该使用什么方法进行异步?
在这里,它还取决于您的要求和您的 .Net 版本。如果您使用的是 .NET 4.5,则使用异步等待执行此操作的最简单方法。如果您使用的是.Net 3.5,则仅使用Task。如果 .Net 2 使用 BackgorundWorker ,则使用 Thread 类。 只有异步方法必须获得单词 async。其他方法您不必更改它们。换句话说,只有阻止 UI 的方法。
您当前的代码没有任何意义。
在 UI 应用程序中async
代码的要点是响应能力 - 即将长时间运行的操作移出 UI 线程。正如@Gusdor指出的那样,async
的大多数用例都是基于 I/O(或基于事件)的操作,您不希望仅仅为了等待某些结果而阻止 UI 线程。另一个用例是,当您有一些 CPU 密集型工作要做,但您不想占用 UI 线程时;在这种情况下,您可以使用 Task.Run
.
但是在您的代码中,您使用 TaskScheduler.FromCurrentSynchronizationContext
调用 StartNew
,这意味着您的"子"任务将在 UI 线程上执行。因此,您的OnAddUserControl1
只是启动将在同一线程上运行并异步等待它们完成的任务。这是一种非常复杂的无所事事的方式。
当我们讨论StartNew
的主题时,还有许多其他问题:
- 代码传递
CancellationToken
,而从未在委托中观察它。 - 代码指定
AttachedToParent
这对于await
兼容的任务是不正确的。 - 如上所述,代码正在传递一个
TaskScheduler
,该将直接在 UI 线程上运行委托。
如果需要使用后台(线程池)任务,则应使用 Task.Run
而不是 Task.Factory.StartNew
;我在我的博客上详细介绍了。
因此,对于此示例,使用 async
或 await
根本没有意义。
开始使用async
的最佳方法是首先识别 I/O 绑定(或事件驱动)部分(例如,HTTP 请求、数据库调用),使它们async
,然后沿着调用堆栈向上移动。