If you have an async method, like the one below:
private async Task DoAsync()
{
Console.WriteLine(@"(1.1)");
Thread.Sleep(200);
Console.WriteLine(@"(1.2)");
await Task.Delay(1000);
Console.WriteLine(@"(1.3)");
}
and you call it asynchronously with Dispatcher:
Console.WriteLine(@"(1)");
await Application.Current.Dispatcher.InvokeAsync(DoAsync);
Console.WriteLine(@"(2)");
The output you'll get will be: (1) (1.1) (1.2) (2) (1.3)
If you use Dispatcher.BeginInvoke() and you'll wait for Completed event, the effect will be the same (which is expected):
Console.WriteLine(@"(1)");
var dispatcherOp = Dispatcher.BeginInvoke(new Func<Task>(DoAsync));
dispatcherOp.Completed += (s, args) =>
{
Console.WriteLine(@"(2)");
};
What we see here is that the await in DoAsync() method makes Dispatcher believe the operation ended.
My question: is it a bug or a feature? Do you know any document that describes this behavior? I couldn't find anything.
I'm not asking for a workaround.
It is a bug in your code, the object returned from Application.Current.Dispatcher.InvokeAsync(DoAsync);
is a Task<Task>
, you only await the outer task, not waiting for the inner task to complete. These situations is what .Unwrap()
is for.
Console.WriteLine(@"(1)");
await Application.Current.Dispatcher.InvokeAsync(DoAsync).Unwrap();
Console.WriteLine(@"(2)");
The output you will get will be: (1) (1.1) (1.2) (1.3) (2)
What Unwrap is doing is effectively turning your code in to
Console.WriteLine(@"(1)");
await (await Application.Current.Dispatcher.InvokeAsync(DoAsync));
Console.WriteLine(@"(2)");
But with a nicer looking format.
For documentation see "How to: Unwrap a nested task"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With