WPF全局异常处理程序

Sco*_*son 322 .net c# wpf exception-handling exception

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

实现全局Try/Catch块的最佳位置在哪里.至少我必须实现一个消息框:"抱歉给您带来不便......"

Dre*_*kes 498

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

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

您应该考虑捕获未处理的异常所需的级别.

#2和#3之间的决定取决于您是否使用多个WPF线程.这是一种非常奇特的情况,如果你不确定自己是否存在,那么你最有可能不是.

  • 此外,我们必须对项目#1使用**`AppDomain.CurrentDomain.UnhandledException`**. (27认同)
  • 很高兴看到每个选项的汇编和解释.以下是我目前正在接近在应用程序级别记录未处理的异常的方法:https://gist.github.com/ronnieoverby/7568387 (17认同)
  • 注意你的项目#3,我不得不把.Current跟在应用程序后面这样:Application.Current.DispatcherUnhandledException + = ... (14认同)
  • 如果你现在使用Async tasks/TaskScheduler,我相信`TaskScheduler.UnobservedTaskException + = ...`也与这些正交. (2认同)
  • 10 年后...我继承了一个带有次优异常处理的 WPF 应用程序,并且正在对我应该处理哪些事件进行一些研究,并找到了这个答案和我自己的建议。感谢互联网增强了我的长期记忆。 (2认同)

Tho*_*que 161

你可以处理这个AppDomain.UnhandledException事件

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

  • 如果您创建窗口的多个实例,那就太糟糕了... (11认同)
  • 在表单构造函数中添加处理程序,如下所示:AppDomain.Current.UnhandledException + = ... (10认同)
  • 可以在App.xaml.cs添加处理程序我想 (6认同)

Ser*_*gey 113

Application.Dispatcher.UnhandledException的代码的快速示例:

public App() {
    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);
    // OR whatever you want like logging etc. MessageBox it's just example
    // for quick debugging etc.
    e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,在某些情况下,设置`e.Handled = true`会导致应用程序UI关闭,而进程仍然在计算机上静默运行. (19认同)
  • 我认为这将是一个更好的检查`e.Handled = MainWindow?.IsLoaded ?? 假;`。这将确保“e.Handled”仅在主窗口已加载时才为“true”。 (2认同)

jur*_*rev 41

我在WPF应用程序中使用以下代码,以便在出现未处理的异常时显示"抱歉给您带来的不便"对话框.它显示异常消息,并询问用户是否要关闭应用程序或忽略异常并继续(当非致命异常发生且用户仍可正常继续使用该应用程序时,后一种情况很方便).

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

<Application .... Startup="Application_Startup">
Run Code Online (Sandbox Code Playgroud)

在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();
    } 
}
Run Code Online (Sandbox Code Playgroud)

  • @McKay被删除作为一个骗局:http://stackoverflow.com/questions/2004629/what-is-the-best-way-in-c-sharp-to-determine-whether-the-programmer-is-运行-T (2认同)

Mov*_*GP0 17

最佳答案可能是/sf/answers/103079371/.

以下是一些显示如何使用它的代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 而不是`#if DEBUG`你应该使用`RegisterGlobalExceptionHandling`上的`[Conditional("DEBUG")]`属性.这样,您可以确保在更改编译器目标时编译代码. (3认同)

Tob*_*fer 11

除了上面的帖子:

Application.Current.DispatcherUnhandledException
Run Code Online (Sandbox Code Playgroud)

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

 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);
        }
    });
Run Code Online (Sandbox Code Playgroud)