为什么即使在WPF应用程序生命周期中处理程序是async void,Application.Exit事件仍然有效?

时间:2013-09-05 13:15:51

标签: c# .net wpf asynchronous application-lifecycle

我有一个问题如何等待WPF生命周期方法中的异步方法(使用Caliburn-Micro框架)(例如OnActivate,OnInitialized,OnExit - 它直接绑定到 Application.Exit 事件)

这篇文章准确地描述了我的问题:http://mark.mymonster.nl/2013/07/10/donrsquot-make-your-application-lifetime-events-async-void(现在我正在考虑使用本文中的解决方案,但第一次看起来有点矫枉过正)

我需要在OnExit hanlder中等待一些异步方法,所以我把它作为异步。它有效。的种类。 我不明白为什么?? ,但是在调用Application.Exit事件时,它会以某种方式等待,直到方法完成,即使处理程序是异步void。 你能解释一下这是怎么回事吗?这样安全吗?或者只是自信? Async void只能用于顶级事件,是这种情况吗?

我查看了System的代码。绑定看起来像这样:

public event EventHandler Exit
{
  add
  {
    XcpImports.CheckThread();
    this.AddEventListener(DependencyProperty.RegisterCoreProperty(20053U, (Type) null), (Delegate) value);
  }
  remove
  {
    XcpImports.CheckThread();
    this.RemoveEventListener(DependencyProperty.RegisterCoreProperty(20053U, (Type) null), (Delegate) value);
  }
}

这真是神秘,我无法通过调用此事件来了解.net框架中发生了什么。

奇怪的是,当我不使用 ConfigureAwait(false)时,在处理程序中调用等待Task.Delay(1)会导致死锁。所以我想说在.net代码深处使用了 .Wait()

注意:当我按照预期制作OnActivate,OnInitialized处理程序async时,页面不会等到处理程序完成。

谢谢你的回答!

1 个答案:

答案 0 :(得分:10)

理论上,框架可以检测async void的使用并等到async void方法返回。我在article on SynchronizationContext中描述了详细信息。 AFAIK,ASP.NET是唯一一个等待async void处理程序的内置框架。

WPF async void方法有任何特殊处理。因此,您的退出处理程序正在完成的事实只是巧合。我怀疑你await的操作已经完成或非常快,这使得你的处理程序可以同步完成。

尽管如此,我不推荐您引用的文章中的解决方案。相反,处理窗口的Closing事件,启动您需要执行的任何异步保存,并取消关闭命令(并考虑立即隐藏窗口)。异步操作完成后,再次关闭窗口(并允许它关闭此时间)。我使用这种模式进行异步窗口级“关闭”动画。

我无法重现您描述的僵局。我创建了一个新的.NET 4.5 WPF应用程序,并添加了一个退出处理程序:

private async void Application_Exit(object sender, ExitEventArgs e)
{
    await Task.Delay(1);
}

但没有观察到僵局。事实上,即使使用Task.Yield,在执行await之后也没有任何内容,这就是我所期望的。