有时候,在不可复制的情况下,我的WPF应用程序崩溃了,没有任何消息。该应用程序立即关闭。
哪里是实现全局Try / Catch块的最佳位置。至少我必须用以下消息实现消息框:“抱歉给您带来的不便...”
#1 楼
您可以处理AppDomain.UnhandledException
事件编辑:实际上,此事件可能更合适:
Application.DispatcherUnhandledException
评论
将处理程序添加到表单构造函数中,如下所示:AppDomain.Current.UnhandledException + = ...
– Dabblernl
09-09-24 15:47
如果您创建窗口的多个实例,那就不好了...
–托马斯·莱维斯克
09-09-24 15:50
嗨,托马斯,谢谢你的回答。 Appdomain.UnHandledException对我来说很棒。
–斯科特·奥尔森(Scott Olson)
09年9月28日在9:12
可以在App.xaml.cs中添加处理程序
–乔治·比尔比利斯(George Birbilis)
2014年4月3日在20:24
@FranzKiermaier您正在使用MVVM的事实不应更改任何内容...
–托马斯·莱维斯克
20 Jan 24 '15:10
#2 楼
您可以在不同级别捕获未处理的异常:AppDomain.CurrentDomain.UnhandledException
来自AppDomain中的所有线程。Dispatcher.UnhandledException
来自单个特定的UI调度程序线程。 Application.Current.DispatcherUnhandledException
来自WPF应用程序中的主UI调度程序线程。来自每个使用任务调度程序进行异步操作的AppDomain内的
TaskScheduler.UnobservedTaskException
。您应该考虑在哪个级别捕获未处理的异常。
在#2和#3之间进行选择取决于您是否使用多个WPF线程。这是一个非常特殊的情况,如果您不确定是否要这样做,则很可能您不确定。
评论
请注意您的项目#3,我必须将.Current放在这样的Application后面:Application.Current.DispatcherUnhandledException + = ...
– Keith G
2011-3-16在20:57
@Keith G-所有这些事件都是实例成员,因此您需要根据情况将它们挂接到所需的每个对象上。
–德鲁·诺克斯(Drew Noakes)
2011-3-17在0:29
同样,我们必须对项目#1使用AppDomain.CurrentDomain.UnhandledException。
–Rev
2012年5月29日4:21
如果您现在正在使用异步任务/ TaskScheduler,我相信TaskScheduler.UnobservedTaskException + = ...也与此正交。
– DuckMaestro
2012年9月22日23:23
很高兴看到这些选项的汇编以及每个选项的说明。这是我目前正在应用程序级别记录未处理的异常的方式:gist.github.com/ronnieoverby/7568387
–罗尼·奥弗比(Ronnie Overby)
13年20月20日在18:29
#3 楼
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;
}
我将此代码添加到App.xaml.cs
中
评论
+1用于剪切/粘贴代码。如果您想为错误消息对话框增添趣味,则WPF扩展工具包具有消息框控件。
–阿伦M
2011年3月26日14:48
请注意,在某些情况下,设置e.Handled = true可能导致应用程序UI关闭,而进程仍在计算机上静默运行。
– qJake
2014年5月23日14:42
警告!在未处理的顶级异常中使用MessageBox.Show()可能导致进程挂起!登录或执行其他操作,但不要使用此API或显示任何UI。
–克里斯·鲍德曼(Chris Bordeman)
18/12/24在1:18
@qJake能否请您更好地描述这种情况?
– Francesco Bonizzi
20年7月16日在12:48
#4 楼
每当发生未处理的异常时,我都会在WPF应用程序中使用以下代码来显示“抱歉给您带来的不便”对话框。它显示异常消息,并询问用户是否要关闭该应用程序或忽略该异常并继续(当发生非致命异常并且用户仍可以正常继续使用该应用程序时,后一种情况很方便)。 >在App.xaml中添加启动事件处理程序:
<Application .... Startup="Application_Startup">
在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();
}
}
评论
@韦斯顿那个链接已经死了
–麦凯
15年7月29日在18:23
@McKay被删除为虚假信息:stackoverflow.com/questions/2004629/…
–weston
15年7月29日在18:26
@McKay没问题。仅供参考,它引发了一个元问题meta.stackoverflow.com/questions/300452/…
–weston
15年7月30日在14:02
只是关闭而不给用户机会保存更改仍然有点邪恶。如果这是暂时的网络故障该怎么办?
–enorl76
17-10-21在22:51
警告!在未处理的顶级异常中使用MessageBox.Show()可能导致进程挂起!登录或执行其他操作,但不要使用此API或显示任何UI。
–克里斯·鲍德曼(Chris Bordeman)
18/12/24在1:19
#5 楼
最佳答案可能是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);
}
}
评论
可能需要包括#if DEBUG,以便Visual Studio仅在调试时才处理像正常一样的异常。很棒的解决方案。
–詹姆斯M
16年11月1日在9:02
而不是#if DEBUG,应该在RegisterGlobalExceptionHandling上使用[Conditional(“ DEBUG”)]属性。这样,您可以确保更改编译器目标时代码可以编译。
–MovGP0
16 Dec 5'在16:28
此外,最好还是在生产代码中保留全局异常的日志记录。您可以在您的依赖项注入设置中将ConditionalAttribute用于记录器的配置,而只需更改记录的详细程度即可。
–MovGP0
16 Dec 5'在16:33
#6 楼
除了上面的帖子之外,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);
}
});
#7 楼
为了补充托马斯的答案,Application
类还具有您可以处理的DispatcherUnhandledException
事件。#8 楼
完整的解决方案在这里用示例代码对其进行了很好的解释。但是,请注意不要关闭应用程序。添加行
Application.Current.Shutdown();。
正常关闭应用程序。
#9 楼
如上所述,Application.Current.DispatcherUnhandledException将无法捕获从另一个线程(然后是主线程)引发的异常。
实际情况取决于线程是如何创建的br />如果在主线程以外的其他线程上运行Forms,则需要从每个此类线程中设置Application.ThreadException
评论
从其他线程在SO处复制Hertzel Guinness的答案:app.config中的
–乔治·比尔比利斯(George Birbilis)
15年11月27日,0:09
评论
要爱重复的链接如何回到这个问题这个问题有更好的答案。