C# WPF 全局异常处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1472498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF global exception handler
提问by Scott Olson
Sometimes, under not reproducible circumstances, my WPF application crashes without any message. The application simply close instantly.
有时,在不可重现的情况下,我的 WPF 应用程序崩溃而没有任何消息。该应用程序只需立即关闭。
Where is the best place to implement the global Try/Catch block. At least I have to implement a messagebox with: "Sorry for the inconvenience ..."
哪里是实现全局 Try/Catch 块的最佳位置。至少我必须实现一个消息框:“抱歉给您带来不便......”
采纳答案by Thomas Levesque
You can handle the AppDomain.UnhandledException
event
你可以处理AppDomain.UnhandledException
事件
EDIT: actually, this event is probably more adequate: Application.DispatcherUnhandledException
编辑:实际上,这个事件可能更合适: Application.DispatcherUnhandledException
回答by Drew Noakes
You can trap unhandled exceptions at different levels:
您可以在不同级别捕获未处理的异常:
AppDomain.CurrentDomain.UnhandledException
From all threads in the AppDomain.Dispatcher.UnhandledException
From a single specific UI dispatcher thread.Application.Current.DispatcherUnhandledException
From the mainUI dispatcher thread in your WPF application.TaskScheduler.UnobservedTaskException
from within each AppDomain that uses a task scheduler for asynchronous operations.
AppDomain.CurrentDomain.UnhandledException
来自 AppDomain 中的所有线程。Dispatcher.UnhandledException
来自单个特定的 UI 调度程序线程。Application.Current.DispatcherUnhandledException
从WPF 应用程序中的主UI 调度程序线程。TaskScheduler.UnobservedTaskException
来自每个使用任务调度程序进行异步操作的 AppDomain。
You should consider what level you need to trap unhandled exceptions at.
您应该考虑在什么级别捕获未处理的异常。
Deciding between #2 and #3 depends upon whether you're using more than one WPF thread. This is quite an exotic situation and if you're unsure whether you are or not, then it's most likely that you're not.
在#2 和#3 之间做出决定取决于您是否使用了多个 WPF 线程。这是一种非常奇特的情况,如果您不确定自己是否是,那么很可能您不是。
回答by dustyburwell
To supplement Thomas's answer, the Application
class also has the DispatcherUnhandledException
event that you can handle.
为了补充 Thomas 的回答,该Application
课程还有DispatcherUnhandledException
您可以处理的事件。
回答by Sergey
A quick example of code for Application.Dispatcher.UnhandledException:
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;
}
I added this code in App.xaml.cs
我在 App.xaml.cs 中添加了此代码
回答by jurev
I use the following code in my WPF apps to show a "Sorry for the inconvenience" dialog box whenever an unhandled exception occurs. It shows the exception message, and asks user whether they want to close the app or ignore the exception and continue (the latter case is convenient when a non-fatal exceptions occur and user can still normally continue to use the app).
我在 WPF 应用程序中使用以下代码在发生未处理的异常时显示“抱歉给您带来的不便”对话框。显示异常信息,询问用户是关闭应用还是忽略异常继续(后一种情况在发生非致命异常并且用户仍然可以正常继续使用应用时方便)。
In App.xaml add the Startup event handler:
在 App.xaml 中添加启动事件处理程序:
<Application .... Startup="Application_Startup">
In App.xaml.cs code add Startup event handler function that will register the global application event handler:
在 App.xaml.cs 代码中添加将注册全局应用程序事件处理程序的启动事件处理程序函数:
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();
}
}
回答by Tobias Hoefer
In addition to the posts above:
除了上面的帖子:
Application.Current.DispatcherUnhandledException
will not catch exceptions that are thrown from another thread then the main thread. You have to handle those exceptions on its actual Thread. But if you want to Handle them on your global exception handler you can pass it to the main thread:
不会捕获从另一个线程然后是主线程抛出的异常。您必须在其实际线程上处理这些异常。但是如果你想在你的全局异常处理程序上处理它们,你可以将它传递给主线程:
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);
}
});
回答by Jens
As mentioned above
正如刚才提到的
Application.Current.DispatcherUnhandledException will not catch exceptions that are thrown from another thread then the main thread.
Application.Current.DispatcherUnhandledException 不会捕获从另一个线程然后是主线程抛出的异常。
That actual depend on how the thread was created
这实际取决于线程的创建方式
One case that is not handled by Application.Current.DispatcherUnhandledException is System.Windows.Forms.Timer for which Application.ThreadException can be used to handle these if you run Forms on other threads than the main thread you will need to set Application.ThreadException from each such thread
Application.Current.DispatcherUnhandledException 不处理的一种情况是 System.Windows.Forms.Timer,如果您在主线程以外的其他线程上运行 Forms,则可以使用 Application.ThreadException 来处理这些情况,您需要设置 Application.ThreadException从每个这样的线程
回答by karpanai
回答by MovGP0
Best answer is probably https://stackoverflow.com/a/1472562/601990.
最佳答案可能是https://stackoverflow.com/a/1472562/601990。
Here is some code that shows how to use it:
下面是一些展示如何使用它的代码:
App.xaml.cs
应用程序.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);
}
}