Search code examples
c#wpfasync-awaitdispatcher

Is Dispatcher.BeginInvoke() without await still executed asynchronous?


I have a hard time understanding the connection between the asynchrnous methods of the dispatcher and async/await.

In my case I have an event handler that executes an operation on the dispatcher:

 private void OnEventOccurred(object sender, EventArgs e)
 {
     someControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeLongRunningOperation());
 }

This should not block the UI thread, right? At least it feels like it in our application. What is the difference to the version with async/await?

 private async void OnEventOccurred(object sender, EventArgs e)
 {
     await someControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeLongRunningOperation());
 }

This also works and doesn't seem to make a difference in terms of UI responsiveness.


Solution

  • This should not block the UI thread, right?

    SomeLongRunningOperation() will indeed run on and block the UI thread. The point of awaiting the BeginInvoke method is that your event handler will resume once SomeLongRunningOperation() has finished executing on the UI thread. So if you don't do anything after the call the BeginInvoke, there is no point of using the await keyword here.

    When you do the following, the MessageBox will be displayed before the SomeLongRunningOperation method has finished:

    private void OnEventOccurred(object sender, EventArgs e)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(SomeLongRunningOperation));
        MessageBox.Show("SomeLongRunningOperation will be executed eventually!");
    }
    

    And when you do the following, it will be display after SomeLongRunningOperation has finished:

    private async void OnEventOccurred(object sender, EventArgs e)
    {
        await Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(SomeLongRunningOperation));
        MessageBox.Show("SomeLongRunningOperation has been executed!");
    }
    

    So it's pointless to await the call to BeginInvoke if you don't intend to anything in your event handler after the method has returned.

    Note that everything runs on the same thread here though. If SomeLongRunningOperation is a potentially long-running operation, you should execute it on a background thread. The easiest way to do this would be to start a Task, which you may await:

    await Task.Run(SomeLongRunningOperation);