在C#5中将WPF事件处理程序声明为“异步"的意义 [英] Significance of declaring a WPF event handler as 'async' in C# 5

查看:184
本文介绍了在C#5中将WPF事件处理程序声明为“异步"的意义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Imagine a WPF code-behind event handler:

<Button Click="OnButtonClick" />

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

In C# 4 you would declare your handler as:

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

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

In C# 5 you can declare an async handler

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

那么WPF对此做了什么?几分钟的搜索并没有发现任何问题.

So what is WPF doing with this? A few minutes of searching about didn't turn anything up.

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

It seems that it's possible to perform UI updates after await statements. Does this imply that the task is continued on the Dispatcher thread?

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

If the Task raised an error, would it be raised through the WPF Dispatcher, or only via the TaskScheduler?

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

Are there any other interesting aspects to this that might be nice to understand?

推荐答案

您可能会发现我的异步/等待简介很有帮助.

You may find my async/await intro helpful.

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

An async method is re-written by the compiler to support the await operator. Every async method starts out synchronous (in this case, on the UI thread) until it awaits some operation (that is not already completed).

默认情况下,将保存上下文,并且当操作完成时,该方法的其余部分计划在该上下文中执行.除非为null,否则此处的上下文"为SynchronizationContext.Current,在这种情况下为TaskScheduler.Current.正如Drew所指出的那样,WPF提供了一个DispatcherSynchronizationContext,该DispatcherSynchronizationContext与WPF Dispatcher相关.

By default, the context is saved, and when the operation completes, the rest of the method is scheduled to execute in that context. The "context" here is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. As Drew pointed out, WPF provides a DispatcherSynchronizationContext which is tied to the WPF Dispatcher.

关于错误处理:

当您在WPF async void事件处理程序中await一个Task时,错误处理如下:

When you await a Task inside a WPF async void event handler, the error handling goes like this:

  • Task完成时出现错误.像所有Task错误一样,该异常也包装在AggregateException中.
  • await操作员看到Task完成但有错误.它将取消包装原始异常并重新引发它,从而保留原始堆栈跟踪.
  • async void方法构建器捕获从async void方法转义的异常,并将其传递到async void方法开始执行时处于活动状态的SynchronizationContext(在这种情况下,相同的WPF上下文)./li>
  • Dispatcher上引发了异常(具有原始堆栈跟踪,并且没有任何令人讨厌的AggregateException包装).
  • The Task completes with an error. The exception is wrapped into an AggregateException, like all Task errors.
  • The await operator sees that the Task completed with an error. It unwraps the original exception and re-throws it, preserving the original stack trace.
  • The async void method builder catches the exception escaping from an async void method and passes it to the SynchronizationContext that was active when the async void method started executing (in this case, the same WPF context).
  • The exception is raised (with the original stack trace, and without any annoying AggregateException wrapping) on the Dispatcher.

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

This is rather convoluted, but the intent is to have exceptions raised from async event handlers be practically the same as exceptions raised from regular event handlers.

这篇关于在C#5中将WPF事件处理程序声明为“异步"的意义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆