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