2011-01-26 11 views
12

Okno dialogowe okna WPF jest pokazane za pomocą metody ShowDialog w klasie okna, jak w przypadku naciśnięcia przycisku w oknie głównym, jak to.WPF ShowDialog przełykanie wyjątki podczas obciążenia okna

 private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      try 
      { 
       var window = new Window1(); 
       window.ShowDialog(); 
      } 
      catch (ApplicationException ex) 
      { 
       MessageBox.Show("I am not shown."); 
      } 
     } 

Okno ma załadowaną zdarzenie subskrybowanego w XAML tak:

<Window x:Class="Stackoverflow.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Window1" Loaded="Window_Loaded"> 
    <Grid /> 
</Window> 

jest wyjątek w przypadku Window_Loaded

private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     throw new ApplicationException(); 
    } 

jednak wyjątek nie jest catched przez złapać wokół wywołania ShowDialog, ani nie zwraca połączenia. Wyjątek jest połknięty, a okno nadal wyświetlane.

Dlaczego tak się dzieje i jak mam poradzić sobie z wyjątkiem w zdarzeniu Window_Loaded w oknie WPF? Czy muszę go przechwycić w module obsługi zdarzenia i ręcznie usunąć okno?

W WinForms trzeba zadzwonić Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)

aby pozwolić wyjątków bańki poprzez zwraca ShowDialog. Czy istnieje podobny przełącznik, który należy ustawić w WPF?

+0

Starałem się odtworzyć sytuację, ale bez powodzenia. Wyjątki są łapane w zwykły sposób. Przypuszczam, że masz uproszczony kod, ale wydaje się, że główny punkt jest w szczegółach. Zapewnij je, a ja postaram się pomóc. –

+0

Dzięki za próbę rozmnażania. Powieliłem problem na bardzo prostym przykładzie z miejsca, w którym wziąłem opublikowany kod źródłowy. Im przy użyciu VS2010. Będę edytować moje pytanie i dodać kilka istotnych informacji do odtworzenia. – vidstige

Odpowiedz

7

Widziałem ten problem tylko na maszynach x64, z kodem skompilowanym za pomocą Any Cpu. Zmiana programu na kompilację jako x84 może go naprawić, ale sam miałem problemy w zależności od naszych złożeń.
Moja jedyna sugestia dotycząca kodu jest następująca, a nawet wtedy nie można jej odebrać. Złap wyjątek i ponownie rzuć go w pracującego w tle.

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    try 
    { 
     /// your code here... 
     throw new ApplicationException(); 
     /// your code here... 
    } 
    catch (Exception ex) 
    { 
     if (IntPtr.Size == 8) // 64bit machines are unable to properly throw the errors during a Page_Loaded event. 
     { 
      BackgroundWorker loaderExceptionWorker = new BackgroundWorker(); 
      loaderExceptionWorker.DoWork += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { runWorkerCompletedEventArgs.Result = runWorkerCompletedEventArgs.Argument; }); 
      loaderExceptionWorker.RunWorkerCompleted += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { throw (Exception)runWorkerCompletedEventArgs.Result; }); 
      loaderExceptionWorker.RunWorkerAsync(ex); 
     } 
     else 
      throw; 
    } 
} 
+0

Wow, zadziałało ... To naprawdę dziwne i przerażające. Nie sądzę, że chcę teraz dowiedzieć się więcej na ten temat. :) Myślałem, że to projekt WPF. Wielkie dzięki! – vidstige

+4

oh, sidenote nie wyrzucaj wyjątku ponownie jak ten "throw ex;" - Lepiej wrócić. Tak jak ten "rzut". – vidstige

+0

Usunąłem rzut "ex".Było tam więcej dla jasności niż cokolwiek innego. Mamy jednak sytuację, w której IntPtr.Size zwraca 4 na maszynie x64, a wyjątek jest nadal zawijany podczas ładowania okna przez odbicie z innego zespołu, więc nie powiedziałbym, że jest to rozwiązanie w 100%. Usunięcie instrukcji If naprawiłoby to jednak. – midspace

0

Miałem podobny problem, a próba zrozumienia, skąd przychodzi, jest frustrująca. Jest kilka rzeczy, które mogą powodować problem.

  • Wywołujesz cokolwiek przed wywołaniem metody InitializeComponent(); ? Wcześniej miałem metodę wywoływania elementów xaml, które nie zostały jeszcze zainicjalizowane.
  • Czy próbowałeś nacisnąć klawisz F10, aby uruchomić aplikację, za pomocą opcji Krok po kroku zobaczysz dokładne rozpoczęcie procesu?
  • Czy sprawdziłeś swoje nazewnictwo? XAML może połknąć błędy, takie jak niewłaściwe pisanie metod, a następnie generowany jest wyjątek w czasie wykonywania, szczególnie dla dostawców DataSet. Byłbyś zaskoczony, co możesz uciec.
  • Złapanie wyjątku przy otwieraniu formularza jest dość fundamentalne, wolałbym spojrzeć na wszystkie osoby zależne (powiązania danych lub XAML) i poradzić sobie z tymi pierwszymi.

Nadzieja te punkty pomóc .......

+0

* nie są wyświetlane żadne inne metody, inne niż podane w pytaniu. InitializeComponents jest sam w konstruktorze obu okien. – vidstige

+0

* Dobra uwaga. Sądzę, że jednym ze sposobów było uruchomienie całego kodu, który może rzucić przed wyświetleniem okna dialogowego. – vidstige

1

ja też zrekonstruowany swoją odpowiedź w Visual Studio 2010 w pustym WPF 3.5 projektu.

Projekt zachowywał się zgodnie z oczekiwaniami, tzn. Window_Loaded rzucił wyjątek i został przechwycony przez zdarzenie click button.

Więc nie jestem pewien, dlaczego Twój nie działa, może spróbuj opublikować plik App.xml.cs i dowolny inny kod, którego tutaj nie pokazano?

W międzyczasie, myślałem, że chciałbym zwrócić uwagę na kilka rzeczy:

WPF rzeczywiście handle „Uncaught” Wyjątki trochę inaczej WinForms. Spróbuj patrząc na to za przystawkę:

http://msdn2.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx

Wygląda to tak, jakby nie jest dokładnym odpowiednikiem w WPF do metody SetUnhandledExceptionMode (Patrz http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413).Wypróbuj porady dotyczące rejestracji programu obsługi i zobacz, czy to ci pomoże?

Polecam przejście przez twój kod - ustaw punkt przerwania w oknie Zablokowany przez okno i zobacz, co się stanie - zwróć szczególną uwagę na stos wywołań.

Powodzenia!

1

Badając to nieco więcej znalazłem ten osobliwy wpis na blogu opisujący podobny problem.

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

Jak się okazuje może to być 64-bitowa architektura procesora problem. Kto by się domyślił ?! Mogłoby to wyjaśnić, dlaczego niektórzy ludzie nie mogli powtórzyć problemu, moim prostym przykładem. Próbowałem skompilować mój przykład w "Any CPU", x64 i x86, ale bezskutecznie. Na x64 wszystko faktycznie wybuchło, całkowicie zawieszając się w oknie dialogowym Windowsa.

Sądzę więc, że jest to odpowiedź bez weryfikacji jej na 32-bitowym komputerze.

2

„dlaczego” jest wyjaśnione tutaj: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

W skrócie, wyjątek nie może być propagowane w 64-bitowych systemach operacyjnych, ponieważ istnieje przejście między użytkownikiem i trybie jądra.

Test IntPtr.Size w odpowiedzi @midspace nie jest wystarczający, ponieważ IntPtr.Size będzie równe 4 w procesie x86 działającym na x64 os (musisz użyć Environment.Is64BitOperatingSystem zamiast na .NET 4 i nowszych).

Rozwiązanie: użyj innego zdarzenia, na przykład ContentRendered, które jest wywoływane po Loaded lub umieść kod w konstruktorze okna.

Nigdy nie używaj Loaded (lub OnLoad w Winformach), ponieważ jeśli jest tam wyjątek, nie wiesz, co może się stać.

Zobacz także w tej odpowiedzi: https://stackoverflow.com/a/4934010/200443

Powiązane problemy