2011-01-26 9 views
12

Una finestra di dialogo della finestra WPF viene mostrata utilizzando il metodo ShowDialog nella classe Window come quando viene premuto un pulsante nella finestra principale, in questo modo.WPF ShowDialog durante l'inceppamento delle eccezioni durante il caricamento della finestra

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

la finestra ha un evento Loaded sottoscritto nel codice XAML in questo modo:

<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> 

viene generata un'eccezione in caso Window_Loaded

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

Tuttavia l'eccezione non viene catturato dal aggirare la chiamata ShowDialog, né la chiamata restituisce. L'eccezione viene inghiottita e la finestra viene comunque visualizzata.

Perché si verifica questo problema e come gestirò un'eccezione nell'evento Window_Loaded di una finestra WPF? Devo prenderlo nel gestore dell'evento e Smaltire la finestra manualmente?

In WinForms è necessario chiamare Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)

al fine di permettere eccezioni bolla attraverso ShowDialog chiama. C'è un interruttore simile che deve essere impostato su WPF?

+0

ho cercato di riprodurre la vostra situazione, ma senza successo. Le eccezioni sono catturate nel modo usuale. Suppongo che tu abbia il codice semplificato, ma sembra che il punto principale sia nei dettagli. Forniteli e cercherò di aiutare. –

+0

Grazie per aver provato a riprodurlo. Ho riprodotto il problema in un esempio molto semplice da dove ho preso il codice sorgente pubblicato. Sto usando VS2010. Modificherò la mia domanda e aggiungerò alcune informazioni rilevanti per la riproduzione. – vidstige

risposta

7

Ho visto questo problema solo su macchine x64, con codice compilato con Any Cpu. Cambiare il programma da compilare come x84 può risolverlo, ma ho avuto problemi io stesso a seconda dei nostri assemblaggi.
Il mio suggerimento per il codice è il seguente e anche in questo caso non è garantito il ritiro. Individua l'eccezione e la rilancia in un worker in background.

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, ha funzionato ... È davvero strano e spaventoso. Non penso di voler saperne di più su questo ora. :) Ho pensato che fosse un design WPF. Molte grazie! – vidstige

+4

oh, un sidenote non lancia nuovamente l'eccezione come in questo "throw ex;" - Meglio ripensare. Come questo "lancio". – vidstige

+0

Ho rimosso il lancio "ex".Era lì per chiarezza più che altro. Tuttavia, si è verificata una situazione in cui IntPtr.Size restituisce un 4 su una macchina x64 e l'eccezione è ancora oscurata quando si carica una finestra tramite refleciton da un altro assieme, quindi non direi che questa è una soluzione al 100%. La rimozione dell'istruzione If risolverà comunque questa situazione. – midspace

0

Ho avuto un problema simile e cercare di capire dove sta arrivando è frustrante. Ci sono un paio di cose che potrebbero causare un problema.

  • Si sta chiamando qualcosa prima del metodo chiamata InitializeComponent(); ? Precedentemente ho avuto un metodo che chiama gli elementi xaml, che non sono ancora stati inizializzati.
  • Hai provato a premere F10 per avviare l'applicazione, utilizzando Passaggio ti consentirà di vedere l'esatto avvio del processo?
  • Hai controllato la tua denominazione? XAML può ingoiare errori come i metodi che vengono scritti in modo errato e quindi viene generata un'eccezione in fase di esecuzione, in particolare i veri fornitori di DataSet. Saresti sorpreso di quello che puoi farcela.
  • L'acquisizione di un'eccezione per l'apertura di un modulo è piuttosto fondamentale, preferirei esaminare i dipendenti (i collegamenti Data o XAML) e gestirli prima.

Speranza quei punti aiutano .......

+0

* non vengono mostrati altri metodi oltre a quelli indicati nella domanda. InitializeComponents è solo nel costruttore di entrambe le finestre. – vidstige

+0

* Buon punto. Immagino che un modo fosse quello di eseguire tutto il codice che può essere lanciato prima che venga mostrata la finestra di dialogo. – vidstige

1

Ho anche ricostruito la vostra risposta in Visual Studio 2010 in un vuoto progetto WPF 3.5.

Il progetto si è comportato come previsto, cioè Window_Loaded ha gettato l'eccezione ed è stato catturato dall'evento click del pulsante.

Quindi non sono sicuro del motivo per cui il tuo non funziona, forse prova a postare il tuo App.xml.cs e qualsiasi altro codice che non hai mostrato qui?

Nel frattempo, ho pensato vorrei sottolineare un paio di cose:

WPF effettivamente gestire le eccezioni non gestite fanno "" un po 'diverso da WinForms. Prova a guardare questo per un antipasto:

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

Sembra come se non v'è un esatto equivalente in WPF per il metodo SetUnhandledExceptionMode (Vedi http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413).Prova i loro consigli su come registrare un conduttore e vedere se questo ti aiuta?

Suggerirei di passare attraverso il codice - impostare un punto di interruzione in Window_Loaded e vedere cosa succede - prestare particolare attenzione allo stack di chiamate.

Buona fortuna!

1

Ricercando questo un po 'di più ho trovato questa particolare voce di blogging che descrive un problema simile.

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

Come si scopre che potrebbe essere un problema architettura del processore 64 bit. Chi avrebbe mai immaginato ?! Potrebbe spiegare perché alcune persone non sono riuscite a riprodurre il problema nel mio semplice esempio. Ho provato a compilare il mio esempio in "Any CPU", x64 e x86 ma inutilmente. Su x64 l'intera faccenda è esplosa completamente con una finestra di dialogo di crash di Windows.

Quindi immagino che questa sia la risposta senza verificarla su una macchina a 32 bit.

2

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

In breve, l'eccezione non può essere propagato in sistemi operativi a 64 bit perché c'è una transizione tra la modalità kernel utente e.

Il test di IntPtr.Size in @midspace answer non è adeguato perché IntPtr.Size sarà uguale a 4 in un processo x86 in esecuzione su un sistema x64 (è necessario utilizzare Environment.Is64BitOperatingSystem su .NET 4 e versioni successive).

La soluzione ora: utilizzare un altro evento come ContentRendered che viene chiamato dopo lo Loaded o inserire il codice nel costruttore di finestre.

Non utilizzare mai Loaded (o OnLoad in Winforms), perché se c'è un'eccezione lì, non si sa cosa può succedere.

Date un'occhiata anche questa risposta: https://stackoverflow.com/a/4934010/200443

Problemi correlati