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;
    }                
}

我的问题是 - 创建子任务是否有意义,或者没有子任务的代码更好?如果答案是肯定的,那么我应该让所有方法异步吗?如果不是,我不应该使用什么方法进行异步?

async /await for wpf applicationlication中的方法

这些事件订阅真的需要异步吗?您可能过于努力地使用异步代码。

用户控件构造函数通常是最耗时的部分,必须在 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的主题时,还有许多其他问题:

  1. 代码传递CancellationToken,而从未在委托中观察它。
  2. 代码指定AttachedToParent这对于await兼容的任务是不正确的。
  3. 如上所述,代码正在传递一个TaskScheduler,该将直接在 UI 线程上运行委托。

如果需要使用后台(线程池)任务,则应使用 Task.Run 而不是 Task.Factory.StartNew ;我在我的博客上详细介绍了。

因此,对于此示例,使用 asyncawait 根本没有意义。

开始使用async的最佳方法是首先识别 I/O 绑定(或事件驱动)部分(例如,HTTP 请求、数据库调用),使它们async,然后沿着调用堆栈向上移动。