Ответ 1
Вы можете обработать событие AppDomain.UnhandledException
EDIT: на самом деле это событие, вероятно, более адекватно: Application.DispatcherUnhandledException
Иногда при невоспроизводимых обстоятельствах приложение WPF выходит из строя без каких-либо сообщений. Приложение просто мгновенно закрывается.
Где лучшее место для реализации глобального блока Try/Catch. По крайней мере, мне нужно создать почтовый ящик с: "Извините за неудобства..."
Вы можете обработать событие AppDomain.UnhandledException
EDIT: на самом деле это событие, вероятно, более адекватно: Application.DispatcherUnhandledException
Вы можете захватить необработанные исключения на разных уровнях:
AppDomain.CurrentDomain.UnhandledException
От всех потоков в AppDomain.Dispatcher.UnhandledException
От одного конкретного потока диспетчера пользовательского интерфейса.Application.Current.DispatcherUnhandledException
От основного потока диспетчера пользовательского интерфейса в вашем приложении WPF.TaskScheduler.UnobservedTaskException
изнутри каждого AppDomain, который использует планировщик задач для асинхронных операций.Вы должны рассмотреть, какой уровень вам нужен, чтобы захватить необработанные исключения в.
Выбор между # 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 добавьте функцию обработчика событий запуска, которая зарегистрирует обработчик событий глобального приложения:
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();
}
}
Лучший ответ, вероятно, fooobar.com/questions/25861/....
Вот какой код, который показывает, как его использовать:
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
не будет перехватывать исключения, которые выбрасываются из другого потока, а затем основного потока. Вы должны обрабатывать эти исключения в своей реальной теме. Но если вы хотите обработать их в своем глобальном обработчике исключений, вы можете передать его в основной поток:
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);
}
});
Чтобы дополнить Томаса, класс Application
также имеет DispatcherUnhandledException
событие, которое вы можете обработать.
Полное решение здесь
он очень хорошо объяснил пример кода. Однако будьте осторожны, чтобы он не закрыл приложение. Добавьте строку Application.Current.Shutdown(); для изящного закрытия приложения.
Как упоминалось выше
Application.Current.DispatcherUnhandledException не будет ловить исключения, которые выбрасываются из другого потока, а затем основного потока.
Это зависит от того, как был создан поток
Один случай, который не обрабатывается Application.Current.DispatcherUnhandledException - это System.Windows.Forms.Timer, для которого Application.ThreadException может использоваться для обработки этих если вы запустите Forms на других потоках, кроме основного потока, вам нужно будет установить Application.ThreadException из каждого такого потока