将WPF事件处理程序声明为';异步';在C#5中
想象一下事件处理程序背后的WPF代码:将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调度程序引发,还是
<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提供了一个与WPFDispatcher
绑定的DispatchersSynchronizationContext
关于错误处理:
当您在WPFasync void
事件处理程序中等待Task
时,错误处理如下所示:
任务完成时出错。与所有任务
错误一样,异常被包装到一个聚合异常
wait
操作员看到任务完成时出现错误。它打开原始异常并重新抛出,保留原始堆栈跟踪
async void
方法生成器捕获从async void
方法转义的异常,并将其传递给SynchronizationContext
方法开始执行时处于活动状态的async void
方法(在本例中,为同一WPF上下文)
- 在
调度程序
上引发异常(使用原始堆栈跟踪,并且没有任何恼人的聚合异常
包装)
这相当复杂,但目的是让从async
事件处理程序引发的异常实际上与从常规事件处理程序引发的异常相同。谢谢Stephen。启动器的上下文被保存这一事实正是我所缺少的。我想我真的想不出其他有意义的方法。
this.button.Click += async (s,e) => { ... };