Let me just preface this question with a few things:
It works because the buttonWorking_Click
async code (DelayAsync
as well as the async
lambda passed to Task.Run
) does not have a current SynchronizationContext
, whereas the buttonDeadlock_Click
async code (DelayAsync
) does. You can observe the difference by running in the debugger and watching SynchronizationContext.Current
.
I explain the details behind the deadlock scenario in my blog post Don't Block on Async Code.