Поделиться через


DispatcherUnhandledException catches children window Exception before try catch (ShowDialog)

Problem

Application.DispatcherUnhandledException is a solution provided by the .NET Framework to manage any Unmanaged Exception bubbling up to the root of your application (App.AppStartup).

Whilst using this solution I faced a problem when opening new windows from the Dispatcher of the UI Thread. When performing a try/catch around a Window.ShowDialog(), the DispatcherUnhandledException will be invoked before the try/catch.

This basically means that your root exception handler is used instead of higher try/catch. This also imply that using a multi-windowed application and using the DispatcherUnhandledException does not allow you to properly managed any Exception as you will need to know where they come from.

Example

App.xaml.cs

public App()
{
    DispatcherUnhandledException += App_OnDispatcherUnhandledException;
}

private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    Console.WriteLine("Handler #1 An Exception occured in the Root (App.xaml.cs)");
}

 
MainWindow.xaml.cs

private void Button_Click(object sender, RoutedEventArgs e)
{
    ErroringWindow window = new ErroringWindow();
    try
    {
        window.ShowDialog();
    }
    catch (Exception)
    {
        Console.WriteLine("Handler #2 Exception occured in the try/catch");
    }
}

 

You would expect the handler #2 to catch an Exception from the ErroringWindow first.

But here is the result :

> Handler #1 An Exception occured in the Root (App.xaml.cs)

> Handler #2 Exception occured in the try/catch

Solution

The solution is very simple and straightforward. Using a try/catch around all the code of the App.Startup event will let the Exception bubble up the right way and let you manage the UnhandledExceptions in your try/catch.

App.xaml

Remove the StartupUri="MainWindow.xaml" from the App.xaml so that we invoke it in code.

App.xaml.cs

public App()
{
    Startup += OnStartup;
}

private void OnStartup(object sender, StartupEventArgs startupEventArgs)
{
    try
    {
        MainWindow window = new MainWindow();
        window.ShowDialog();
    }
    catch (Exception ex)
    {
        ManageGlobalException(ex);
    }
}

private void ManageGlobalException(Exception ex)
{
    Console.WriteLine("An Exception occured in the Root (App.xaml.cs)");
}

MainWindow.xaml.cs

 private void Button_Click(object sender, RoutedEventArgs e)
{
    ErroringWindow window = new ErroringWindow();
    try
    {
        window.ShowDialog();
    }
    catch (Exception)
    {
        Console.WriteLine("Handler #2 Exception occured in the try/catch");
    }
}

 

Result :

> Exception occured in the try/catch