Wenhui
Wenhui

Reputation: 61

WPF Application Shutdown When Exception Occurs in WindowClosing Method

I find when an exception occurs in MainWindow#Window_Closing method, even I set the e.cancel = true before the exception and e.handled = true in App#DispatcherUnhandledException, the application still shutdown. I set a breakpoint in Application_Exit method and the stacktrace shows the shutdown is called by ExceptionWrapper.InternalRealCall -> Application.ShutdownCallback -> Application.ShutdownImpl -> Application.DoShutdown

Could anybody help me understand why this happens and is there any way to avoid application shutdown when exception happens in Window_Closing method? (I know I can always catch all exception in this method but I'd like to know if there is any better approach to avoid unexpected exception kill the application)

Below is sample code to reproduce this issue. Click the window close button to reproduce this issue.

Thanks.

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        e.Cancel = true;
        throw new Exception();
    }
}

App.xaml.cs

public partial class App : Application
{
    private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
    {
        e.Handled = true;
    }
    private void Application_Exit(object sender, ExitEventArgs e)
    {
        var exitCode = e.ApplicationExitCode;
    }
}

App.xaml

<Application x:Class="WpfApplication1.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:WpfApplication1"
         StartupUri="MainWindow.xaml" DispatcherUnhandledException="Application_DispatcherUnhandledException" Exit="Application_Exit">

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" Closing="Window_Closing">

Upvotes: 2

Views: 3066

Answers (3)

iammukeshm
iammukeshm

Reputation: 31

I came across this few days back during one of my WPF projects. Yes, it is possible to prevent the application from shutting down on unhandled exceptions. Just let the application know that the exception is handled so that the application does not take additional actions. Makes sense right?

Wherever you initialize the application or have access to the Application Instance, add an event 'DispatcherUnhandledException' to the object of the instance. You will preferably have to add the event invoke function to App.xaml.cs of your WPF project.

Add this to the Constructor of App.

 Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;

Then add the Current_DispatcherUnhandledException function within the same class.

public static void Current_DispatcherUnhandledException (object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        var errorBox = new Core.Common.UI.WPF.MessageBox();
        errorBox.Error(e.Exception.Message);
        //Log to Database
        var logger = Logger.NLogger.GetLogger("My-Logger");
        logger.Error(e.Exception, e.Exception.Message);
        e.Handled = true;
    }

You could also Log the exceptions externally to DB, File System. e.Handled = true; This line tells the application that the exception is handled and not to worry about it.

PRO TIP - Make sure no exceptions happen within the DispatcherHandledException, else the Application will still close down.

Upvotes: 0

simon at rcl
simon at rcl

Reputation: 7344

It's fine catching the DispatcherUnhandledException, but that's not the end of it. If you catch it and set Handled to true, then the application just says OK, and shuts down. If Handled is set false, it says 'Still needs a bit of a check' and then if the AppDomain UnhandledException is set it calls that:

In your App.xaml.cs file:

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    e.Handled = false;
}

private void Application_Startup(object sender, StartupEventArgs e)
{
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}

private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    MessageBox.Show(string.Format("Is Terminating: {0}\r\n{1}", e.IsTerminating, e.ExceptionObject.ToString()));
}

Here the CurrentDomain_UnhandledException method is only called is I set Handled to false. Either way, the apps going down.

Note that UnhandledExceptionEventArgs doesn't have a Handled property, but it does have an IsTerminating one. I'm not sure under what circumstances that would be false, though.

EDIT - Turns out that IsTerminating will only be false when compatibility is set to .NET 1.0 and 1.1 as in those versions of the framework an unhandled exception in some background threads would not cause the app to close. Since 2.0, all unhandled exceptions will cause the app to close.

Upvotes: 2

GazTheDestroyer
GazTheDestroyer

Reputation: 21261

If you look at the WPF source, you will see that this is by design. There is even an explicit comment to that effect:

// Event handler exception continuality: if exception occurs in Closing event handler, the
// cleanup action is to finish closing.
CancelEventArgs e = new CancelEventArgs(false);
try
{
    OnClosing(e);
}
catch
{
    CloseWindowBeforeShow();
    throw;
}

I guess it makes sense, since you wouldn't want a bug to prevent the user closing a window.

Upvotes: 0

Related Questions