将WPF事件处理程序声明为';异步';在C#5中

将WPF事件处理程序声明为';异步';在C#5中,c#,.net,wpf,asynchronous,c#-5.0,C#,.net,Wpf,Asynchronous,C# 5.0,想象一下事件处理程序背后的WPF代码: <Button Click="OnButtonClick" /> 在C#5中,您可以声明一个async处理程序 private async void OnButtonClick(object sender, RoutedEventArgs e) { ... } 那么WPF用这个做什么呢?几分钟的搜索没有发现任何东西 似乎可以在wait语句之后执行UI更新。这是否意味着任务在调度程序线程上继续 如果任务引发错误,是通过WPF调度程序引发,还是

想象一下事件处理程序背后的WPF代码:

<Button Click="OnButtonClick" />
在C#5中,您可以声明一个
async
处理程序

private async void OnButtonClick(object sender, RoutedEventArgs e) { ... }
那么WPF用这个做什么呢?几分钟的搜索没有发现任何东西

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

如果
任务
引发错误,是通过WPF
调度程序
引发,还是仅通过
任务调度程序
引发

是否还有其他有趣的方面值得理解?

部分答案。发件人:

不能等待具有void返回类型的异步方法,并且void返回方法的调用方不能捕获该方法引发的任何异常

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

此外,事件处理程序注册没有任何特定于XAML的操作。这本可以用代码完成:

this.button.Click += OnButtonClick;
甚至作为异步lambda:

this.button.Click += async (s,e) => { ... };
至于
等待
后UI更新的安全性,似乎是在中执行延续,这是每个线程设置的。在WPF中,这是一个与WPF
调度程序耦合的程序,该调度程序首先泵送事件。

您可能会发现我的帮助

编译器重新编写
async
方法以支持
wait
运算符。每个
async
方法都以同步方式启动(在本例中,在UI线程上),直到它
等待某个操作(尚未完成)

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

关于错误处理:

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

  • 任务完成时出错。与所有
    任务
    错误一样,异常被包装到一个
    聚合异常
  • wait
    操作员看到
    任务完成时出现错误。它打开原始异常并重新抛出,保留原始堆栈跟踪
  • async void
    方法生成器捕获从
    async void
    方法转义的异常,并将其传递给
    SynchronizationContext
    方法开始执行时处于活动状态的
    async void
    方法(在本例中,为同一WPF上下文)
  • 调度程序
    上引发异常(使用原始堆栈跟踪,并且没有任何恼人的
    聚合异常
    包装)

这相当复杂,但目的是让从
async
事件处理程序引发的异常实际上与从常规事件处理程序引发的异常相同。

谢谢Stephen。启动器的上下文被保存这一事实正是我所缺少的。我想我真的想不出其他有意义的方法。
this.button.Click += async (s,e) => { ... };