Domyślnie WPF wyświetla okno dialogowe nieobsłużonego błędu a następnie po przyciśnięciu przycisku aplikacja zostaje zamknięta. W poście zajmiemy jednak się przeładowaniem tego zachowania poprzez np. zapis błędu do pliku. W WPF możemy wykorzystać zdarzenie DispatcherUnhandledException(plik App.xaml.cs), która wywoływana jest dla nieobsłużonych wyjątków. Jeśli zatem w kodzie znajdzie się wywołanie throw bez klauzuli catch, zdarzenie DispatcherUnhandledException zostanie uruchomione. Przykład, plik app.xaml.cs
public partial class App : Application { private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { // zapis do logów, wyświetlanie własnego okna błędów itp. e.Handled = true; } }
app.xaml:
<Application x:Class="WpfApplication2.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" DispatcherUnhandledException="App_DispatcherUnhandledException" StartupUri="MainWindow.xaml"> <Application.Resources> </Application.Resources> </Application>
Ustawienie wartości e.Handled na true powoduje, że wyjątek zostanie potraktowany jako obsłużony. Jest to więc doskonałe miejsce na wyświetlenie wszelkich customowych okien dialogowych czy umieszczenie po prostu logger’a. W pliku XAML podpinamy tylko zdarzenie (DispatcherUnhandledException ).
Niestety powyższy kod będzie działał wyłącznie w sytuacji gdy to główny wątek wyrzuca wyjątek. Dla wszelkich innych wątków (np. w BackgroundWorker, Thread itp), metoda NIE zostanie wywołana. Jeśli zatem chcemy dodać obsługę wyjątków wyrzuconych w zewnętrznych wątkach, musimy:
-
obsłużyć wyjątek w zewnętrznym wątku (catch),
-
przekazać wyjątek poza wątek (czyli do głównego wątku)
-
rethrow – wyrzucić ponownie wyjątek – w tym momencie zostanie już uruchomiona metoda App_DisptacherUnhandledException.
Zainteresowało mnie, że dla innych wątków metoda przechwytująca nie zostanie uruchomiona.
Czy w WinForms (zdarzenie UnhandledException w ApplicationEvents) też tak jest?
ThreadException z Application nie wylapie wyjatkow z innych watkow.
Z kolei
AppDomain.CurrentDomain.UnhandledException wylapie ale nie ma tam opcji handled.