I have a problem how to await async methods in WPF life-cycle methods (with Caliburn-Micro framework) (eg. OnActivate, OnInitialized, OnExit - which is bound directly to Application.Exit event)
This article exactly describes my problem: http://mark.mymonster.nl/2013/07/10/donrsquot-make-your-application-lifetime-events-async-void (now I am thinking of using the solution from this article, but seems like a bit overkill for the first look)
I need to await some async methods in my OnExit hanlder so I have it as async. And it works. Kind of. I do not understand why??, but on calling Application.Exit event it somehow waits until the method is completed, even if the handler is async void. Can you explain please how this is possible? And is this safe? Or is it just coicidence? Async void should be used only for Top-Level events, is this that case?
I looked in the code of System. And the binding looks like this:
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);
}
}
which is really cryptic and I cannot see what really happens in .net framework by calling this event.
What is as well strange, that calling await Task.Delay(1) in the handler causes DeadLock when I do not use ConfigureAwait(false). So I would say there is somewhere .Wait() used deep in .net code.
Note: when I make OnActivate, OnInitialized handlers async, as expected, page is not waiting till handler completes.
Thx for your answeres!
It is theoretically possible for a framework to detect the use of
async void
and wait until theasync void
method returns. I describe the details in my article onSynchronizationContext
. AFAIK, ASP.NET is the only built-in framework that will wait onasync void
handlers.WPF does not have any special treatment for
async void
methods. So the fact that your exit handler is completing is just coincidence. I suspect that the operations youawait
are either already complete or extremely fast, which allows your handler to complete synchronously.That said, I do not recommend the solution in the article you referenced. Instead, handle the window's
Closing
event, kick off whatever asynchronous saving you need to do, and cancel the close command (and also consider hiding the window immediately). When the asynchronous operation is complete, then close the window again (and allow it to close this time). I use this pattern for doing asynchronous window-level "close" animations.I'm unable to repro the deadlock you describe. I created a new .NET 4.5 WPF application and added an exit handler as such:
but did not observe a deadlock. In fact, even with using
Task.Yield
, nothing after theawait
is ever executed, which is what I would expect.