我发现当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">
答案 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中没有发生异常,否则应用程序仍将关闭。