在WindowClosing方法中发生异常时WPF应用程序关闭

时间:2016-02-16 16:26:43

标签: c# .net wpf xaml

我发现当MainWindow#Window_Closing方法发生异常时,即使我在异常之前设置了e.cancel = true而在App#DispatcherUnhandledException中设置了e.handled = true,应用程序仍然关闭。 我在Application_Exit方法中设置了一个断点,stacktrace显示了由ExceptionWrapper.InternalRealCall调用的关闭 - > Application.ShutdownCallback - > Application.ShutdownImpl - > Application.DoShutdown

有人可以帮我理解为什么会发生这种情况吗?在Window_Closing方法中发生异常时有没有办法避免应用程序关闭? (我知道我总能在这种方法中捕获所有异常,但我想知道是否有更好的方法来避免意外异常导致应用程序被杀死)

以下是重现此问题的示例代码。单击窗口关闭按钮以重现此问题。

感谢。

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">

3 个答案:

答案 0 :(得分:1)

捕获DispatcherUnhandledException很好,但这不是它的结束。如果你抓住它并将Handled设置为true,那么应用程序只是说OK,然后关闭。如果Handled设置为false,则表示“仍需要检查”,然后如果设置了AppDomain UnhandledException,则调用:

在App.xaml.cs文件中:

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()));
}

这里只调用CurrentDomain_UnhandledException方法,我将Handled设置为false。无论哪种方式,应用程序都会停止运行。

请注意,UnhandledExceptionEventArgs没有Handled属性,但它确实有一个IsTerminating属性。不过,我不确定在什么情况下这会是错误的。

编辑 - 事实证明,当兼容性设置为.NET 1.0和1.1时,IsTerminating将仅为false,因为在这些版本的框架中,某些后台线程中的未处理异常不会导致应用程序关闭。从2.0开始,所有未处理的异常都会导致应用关闭。

答案 1 :(得分:0)

如果你看一下WPF source,你会发现这是设计的。甚至对这种影响有明确的评论:

// 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;
}

我想这是有道理的,因为你不希望有一个bug来阻止用户关闭窗口。

答案 2 :(得分:0)

这几天我在WPF的一个项目中遇到了。是的,可以防止应用程序因未处理的异常而关闭。只需让应用程序知道该异常已处理,即可使该应用程序不执行其他操作。有道理吧?

无论您何时初始化应用程序或有权访问应用程序实例,都将事件'DispatcherUnhandledException'添加到实例的对象。您最好将事件调用函数添加到WPF项目的App.xaml.cs中。

将此添加到App的构造函数中。

 Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;

然后在同一类中添加Current_DispatcherUnhandledException函数。

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;
    }

您还可以将异常从外部记录到DB,文件系统中。 e.Handled = true;此行告诉应用程序已处理异常,不必担心。

专业提示-确保DispatcherHandledException中没有发生异常,否则应用程序仍将关闭。