【问题标题】:Significance of declaring a WPF event handler as 'async' in C# 5在 C# 5 中将 WPF 事件处理程序声明为“异步”的意义
【发布时间】:2012-09-23 22:58:46
【问题描述】:

想象一个 WPF 代码隐藏事件处理程序:

<Button Click="OnButtonClick" />

在 C# 4 中,您可以将处理程序声明为:

private void OnButtonClick(object sender, RoutedEventArgs e) { ... }

在 C# 5 中,您可以声明 async 处理程序

private async void OnButtonClick(object sender, RoutedEventArgs e) { ... }

那么 WPF 对此做了什么?几分钟的搜索没有任何结果。

似乎可以在 await 语句之后执行 UI 更新。这是否意味着任务在 Dispatcher 线程上继续执行?

如果 Task 引发错误,是通过 WPF Dispatcher 引发错误,还是仅通过 TaskScheduler 引发错误?

还有其他有趣的方面可以很好理解吗?

【问题讨论】:

    标签: c# .net wpf asynchronous c#-5.0


    【解决方案1】:

    您可能会发现我的async/await intro 很有帮助。

    编译器重写了async 方法以支持await 运算符。每个async 方法开始同步(在这种情况下,在UI 线程上),直到它awaits 一些操作(尚未完成)。

    默认情况下,会保存上下文,当操作完成时,方法的其余部分会安排在该上下文中执行。这里的“上下文”是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current。正如 Drew 所指出的,WPF 提供了一个与 WPF Dispatcher 绑定的DispatcherSynchronizationContext

    关于错误处理:

    当您在 WPF async void 事件处理程序中 awaitTask 时,错误处理如下所示:

    • Task 完成时出现错误。异常被包装到 AggregateException 中,就像所有 Task 错误一样。
    • await 操作员看到 Task 完成时出现错误。它解开原始异常并重新抛出它,保留原始堆栈跟踪。
    • async void 方法构建器捕获从 async void 方法转义的异常,并将其传递给在 async void 方法开始执行时处于活动状态的 SynchronizationContext(在本例中,相同的 WPF 上下文)。
    • Dispatcher 上引发异常(使用原始堆栈跟踪,并且没有任何烦人的AggregateException 包装)。

    这相当复杂,但其目的是让async 事件处理程序引发的异常与常规事件处理程序引发的异常几乎相同。

    【讨论】:

    • 谢谢斯蒂芬。保存发起人的上下文这一事实是我所缺少的。我想我真的想不出任何其他有意义的方法。
    【解决方案2】:

    部分答案。来自MSDN

    不能等待具有 void 返回类型的异步方法,并且返回 void 的方法的调用者无法捕获该方法抛出的任何异常。

    因此,任何错误只能通过TaskScheduler 获得。

    此外,事件处理程序注册没有任何特定于 XAML 的内容。它可以在代码中完成:

    this.button.Click += OnButtonClick;
    

    甚至作为异步 lambda:

    this.button.Click += async (s,e) => { ... };
    

    至于await 之后 UI 更新的安全性,似乎延续是在每个线程设置的SynchronisationContext.Current 内执行的。在 WPF 中,这是一个 DispatcherSynchronisationContext,它与 WPF Dispatcher 耦合,后者首先启动了事件。

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 2017-07-28
      • 1970-01-01
      • 2021-11-05
      • 1970-01-01
      相关资源
      最近更新 更多