[c#] WPF全局異常處理程序


3 Answers

您可以在不同級別捕獲未處理的異常:

  1. AppDomain.UnhandledException所有線程。
  2. Dispatcher.UnhandledException從一個特定的UI調度程序線程。
  3. Application.DispatcherUnhandledException從您的WPF應用程序中的 UI調度程序線程。
  4. 每個使用任務調度程序進行異步操作的AppDomain中的TaskScheduler.UnobservedTaskException

您應該考慮在什麼級別捕捉未處理的異常。

決定#2和#3取決於您是否使用多個WPF線程。 這是一個非常異乎尋常的情況,如果你不確定你是不是,那很可能你不是。

Question

這個問題在這裡已經有了答案:

有時,在不可重現的情況下,我的WPF應用程序崩潰而沒有任何消息。 該應用程序只需立即關閉。

哪裡是實施全球Try / Catch區塊的最佳地點。 至少我必須實現一個消息框:“對不便帶來的不便...”




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



完整的解決方案在here

它的示例代碼非常好。 但是,請注意它不會關閉應用程序。添加行Application.Current.Shutdown(); 優雅地關閉應用程序。




最佳答案可能是https://.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);
    }
}





Related