async / await for wpf application中的方法

时间:2013-10-17 08:44:22

标签: c# wpf asynchronous

我有这样的疑问。例如,我使用mvvm模式动态创建自定义userControl。所以我发出了一个创建userControl的命令。所以创作看起来像

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

我的问题是 - 是否可以创建子任务,或者更好地拥有没有子任务的代码?如果答案是肯定的,那么我应该让所有方法都异步吗?如果没有,我不应该做什么方法异步?

3 个答案:

答案 0 :(得分:4)

那些事件订阅真的需要异步吗?您可能正在努力使用异步代码。

用户控件构造函数通常是最耗时的部分,必须在UI线程上完成。通常只有在调用某种形式的IO或处理时才需要异步操作;

  • 阅读文件
  • 写文件
  • 处理大型数据集
  • 越过流程边界与服务器或连接设备通信

简而言之,异步任务在这里可能有些过分。

答案 1 :(得分:3)

是否可以创建子任务,或者最好是没有子任务的代码?

这取决于您的要求。如果您的UI将被阻止(冻结)很长时间,您必须创建一个子任务,否则不会!

如果答案是肯定的,那么我应该让所有方法都异步吗?如果没有,我不应该采用什么方法异步?

这也取决于您的要求和您的.Net版本。如果您使用的是.NET 4.5,最简单的方法是使用Async等待。如果您使用的是.Net 3.5而不仅仅是使用Task。如果.Net 2使用BackgorundWorker,则使用Thread类。只有异步方法必须得到单词async。您不必更改它们的其他方法。换句话说,只有阻止UI的方法。

答案 2 :(得分:2)

您当前的代码没有任何意义。

UI应用程序中async代码的要点是响应性 - 即,将长时间运行的操作移出UI线程。正如@Gusdor指出的那样,async的大多数用例都是基于I / O(或基于事件的)操作,您不希望阻止UI线程等待某些结果。另一个用例是当你有一些CPU绑定的工作要做,但你不想绑定UI线程;在这种情况下,您可以使用Task.Run

但在您的代码中,您使用StartNew调用TaskScheduler.FromCurrentSynchronizationContext,这意味着您的“子”任务将在UI线程上执行。所以你的OnAddUserControl1只是启动将在同一个线程上运行并异步等待它们完成的任务。这是一种非常复杂的无所事事的方式。

虽然我们讨论的是StartNew,但还存在许多其他问题:

  1. 代码正在传递CancellationToken而没有在委托中观察它。
  2. 代码指定的AttachedToParent对于await兼容的任务不正确。
  3. 如上所述,代码正在传递TaskScheduler,它将在UI线程上运行委托。
  4. 如果您需要使用后台(线程池)任务,则应使用Task.Run instead of Task.Factory.StartNew;我在博客上详细介绍了。

    因此,对于此示例,使用asyncawait毫无意义。

    开始使用async的最佳方法是首先识别I / O绑定(或事件驱动)部分(例如,HTTP请求,数据库调用),使它们成为async,以及然后按照调用堆栈的方式工作。