Skip to content

WPF Dispatcher BeginInvoke vs. InvokeAsync

jbe2277 edited this page May 25, 2018 · 3 revisions

The WPF Dispatcher class comes with two different methods to execute a delegate asynchronously on the Dispatcher thread:

The major difference between these two methods is how they handle Exceptions.

Quick guideline: If you are using await then prefer InvokeAsync. Otherwise use BeginInvoke.

The following code sample explains the Exception handling behavior of both methods:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Dispatcher.UnhandledException += OnUnhandledException;
    }

    private void OnUnhandledException(object sender, 
        DispatcherUnhandledExceptionEventArgs e)
    {
        MessageBox.Show("UnhandledException");
        // App crashes after raising this event if Handled is not set to true.
        e.Handled = true;   
    }

    private void BeginInvoke1Click(object sender, RoutedEventArgs e)
    {
        // This will raise the UnhandledException event.
        Dispatcher.BeginInvoke((Action)(() => throw new Exception()));
    }

    private async void BeginInvoke2Click(object sender, RoutedEventArgs e)
    {
        // Don't use BeginInvoke when using await as the catch handler is ignored.
        try
        {
            await Dispatcher.BeginInvoke((Action)(() => throw new Exception()));
        }
        catch
        {
            MessageBox.Show("BeginInvoke");  // Will never be called.
        }
    }

    private async void InvokeAsync1Click(object sender, RoutedEventArgs e)
    {
        // This behaves similar to BeginInvoke1Click regarding exception handling.
        await Dispatcher.InvokeAsync(() => throw new Exception());
    }

    private async void InvokeAsync2Click(object sender, RoutedEventArgs e)
    {
        try
        {
            await Dispatcher.InvokeAsync(() => throw new Exception());
        }
        catch
        {
            MessageBox.Show("InvokeAsync");
        }
    }

    private void InvokeAsync3Click(object sender, RoutedEventArgs e)
    {
        // Don't use InvokeAsync without await as the exception is tracked 
        // as unobserved exception and might be missed.
        Dispatcher.InvokeAsync(() => throw new Exception());
    }
}

Further readings

  1. Unobserved Exceptions