WPF全局异常处理程序

有时,在不可重现的情况下,我的WPF应用程序崩溃,没有任何消息。 应用程序只需立即关闭。

哪里是最好的地方来实现全球Try / Catch块。 至少我必须实现一个消息框:“抱歉造成不便…”

你可以处理AppDomain.UnhandledException事件

编辑:实际上,这个事件可能是更充分的: Application.DispatcherUnhandledException

您可以在不同级别捕获未处理的异常:

  1. AppDomain.CurrentDomain.UnhandledException所有线程。
  2. Dispatcher.UnhandledException从一个特定的UI调度程序线程。
  3. Application.Current.DispatcherUnhandledException从您的WPF应用程序中的 UI调度程序线程。
  4. 每个使用任务调度程序进行异步操作的AppDomain中的TaskScheduler.UnobservedTaskException

你应该考虑你需要什么级别来捕捉未处理的异常。

决定#2和#3取决于您是否使用多个WPF线程。 这是相当异乎寻常的情况,如果你不确定你是不是,那么你很可能不是。

Application.Dispatcher.UnhandledException的一个简短代码示例:

  public App() :base() { this.Dispatcher.UnhandledException += OnDispatcherUnhandledException; } void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message); MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); e.Handled = true; } 

我在App.xaml.cs中添加了这个代码

我在我的WPF应用程序中使用下面的代码来显示一个“不便之处”对话框,每当发生未处理的异常。 它显示异常消息,并询问用户是否要关闭应用程序或忽略异常并继续(当非致命异常发生且用户仍能正常继续使用应用程序时,后一种情况很方便)。

在App.xaml中添加启动事件处理程序:

 <Application .... Startup="Application_Startup"> 

在App.xaml.cs代码中,添加将注册全局应用程序事件处理程序的Startup事件处理程序函数:

 using System.Windows.Threading; private void Application_Startup(object sender, StartupEventArgs e) { // Global exception handling Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException); } void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { \#if DEBUG // In debug mode do not custom-handle the exception, let Visual Studio handle it e.Handled = false; \#else ShowUnhandledException(e); \#endif } void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e) { e.Handled = true; string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)", e.Exception.Message + (e.Exception.InnerException != null ? "\n" + e.Exception.InnerException.Message : null)); if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No) { if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes) { Application.Current.Shutdown(); } } 

除了上面的帖子:

 Application.Current.DispatcherUnhandledException 

将不会捕获从另一个线程,然后主线程抛出的异常。 您必须在其实际的线程上处理这些异常。 但是如果你想在你的全局异常处理器上处理它们,你可以把它传递给主线程:

  System.Threading.Thread t = new System.Threading.Thread(() => { try { ... //this exception will not be catched by //Application.DispatcherUnhandledException throw new Exception("huh.."); ... } catch (Exception ex) { //But we can handle it in the throwing thread //and pass it to the main thread wehre Application. //DispatcherUnhandledException can handle it System.Windows.Application.Current.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, new Action<Exception>((exc) => { throw new Exception("Exception from another Thread", exc); }), ex); } }); 

为了补充Thomas的回答, Application类还有DispatcherUnhandledException事件,您可以处理。

完整的解决方案在这里

它的示例代码很好解释。 但是,请注意不要关闭应用程序。添加行Application.Current.Shutdown(); 优雅地关闭应用程序。

最佳答案可能是https://stackoverflow.com/a/1472562/601990

下面是一些代码,显示如何使用它:

App.xaml.cs

 public sealed partial class App { protected override void OnStartup(StartupEventArgs e) { // setting up the Dependency Injection container var resolver = ResolverFactory.Get(); // getting the ILogger or ILog interface var logger = resolver.Resolve<ILogger>(); RegisterGlobalExceptionHandling(logger); // Bootstrapping Dependency Injection // injects ViewModel into MainWindow.xaml // remember to remove the StartupUri attribute in App.xaml var mainWindow = resolver.Resolve<Pages.MainWindow>(); mainWindow.Show(); } private void RegisterGlobalExceptionHandling(ILogger log) { // this is the line you really want AppDomain.CurrentDomain.UnhandledException += (sender, args) => CurrentDomainOnUnhandledException(args, log); // optional: hooking up some more handlers // remember that you need to hook up additional handlers when // logging from other dispatchers, shedulers, or applications Application.Dispatcher.UnhandledException += (sender, args) => DispatcherOnUnhandledException(args, log); Application.Current.DispatcherUnhandledException += (sender, args) => CurrentOnDispatcherUnhandledException(args, log); TaskScheduler.UnobservedTaskException += (sender, args) => TaskSchedulerOnUnobservedTaskException(args, log); } private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log) { log.Error(args.Exception, args.Exception.Message); args.SetObserved(); } private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log) { log.Error(args.Exception, args.Exception.Message); // args.Handled = true; } private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log) { log.Error(args.Exception, args.Exception.Message); // args.Handled = true; } private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log) { var exception = args.ExceptionObject as Exception; var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty; var exceptionMessage = exception?.Message ?? "An unmanaged exception occured."; var message = string.Concat(exceptionMessage, terminatingMessage); log.Error(exception, message); } } 

正如刚才提到的

Application.Current.DispatcherUnhandledException将不会捕获从另一个线程,然后主线程抛出的异常。

这实际上取决于如何创建线程

一个不由Application.Current.DispatcherUnhandledException处理的情况是System.Windows.Forms.Timer,如果您在除主线程之外的其他线程上运行Forms,则可以使用Application.ThreadException来处理这些情况。您将需要设置Application.ThreadException从每个这样的线程