2011-01-26 9 views
12

Un cuadro de diálogo de ventana WPF se muestra utilizando el método ShowDialog en la clase Ventana, como cuando se presiona un botón en la ventana principal, como este.WPF ShowDialog omitiendo excepciones durante la carga de la ventana

 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 ventana tiene un evento Loaded suscrito en el XAML como esto:

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

se produce una excepción en el caso Window_Loaded

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

Sin embargo, la excepción no es apresado por la tomar alrededor de la llamada ShowDialog, ni la devolución de llamadas. La excepción se traga y la ventana todavía se muestra.

¿Por qué sucede esto y cómo voy a manejar una excepción en el evento Window_Loaded de una ventana de WPF? ¿Debo atraparlo en el controlador de eventos y desechar la ventana manualmente?

En WinForms que necesita para llamar Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)

el fin de permitir excepciones de burbujas a través ShowDialog llama. ¿Hay algún cambio similar que deba establecerse en WPF?

+0

traté de reproducir su situación, pero sin éxito. Las excepciones se toman de la manera habitual. Supongo que tienes código simplificado, pero parece que el punto principal está en los detalles. Preséntelos e intentaré ayudar. –

+0

Gracias por intentar reproducir. He reproducido el problema en un ejemplo muy simple desde donde tomé el código fuente publicado. Estoy usando VS2010. Editaré mi pregunta y agregaré información relevante para reproducir. – vidstige

Respuesta

7

Solo he visto este problema en máquinas x64, con código compilado con Any Cpu. Cambiar el programa para compilarlo, ya que x84 puede solucionarlo, pero he tenido problemas allí mismo dependiendo de nuestros ensamblajes.
Mi única sugerencia de código es la siguiente, y aún así no está garantizado para recogerlo. Captura la excepción y vuelve a lanzarla en un trabajador de segundo plano.

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, funcionó ... Eso es realmente extraño y aterrador. No creo que quiera aprender más sobre esto ahora. :) Pensé que era un diseño de WPF. ¡Muchas gracias! – vidstige

+4

oh, una nota al margen no arroje la excepción de nuevo como este "throw ex;" - Mejor volver a lanzar. Como este "tiro". – vidstige

+0

He eliminado el lanzamiento "ex".Estaba allí más por claridad que cualquier otra cosa. Sin embargo, hemos tenido una situación en la que IntPtr.Size devuelve un 4 en una máquina x64 y la excepción todavía se sigue al cargar una ventana a través de refleciton desde otro ensamblaje, por lo que no diría que es una solución al 100%. Sin embargo, eliminar la declaración If arreglaría esto. – midspace

0

Tuve un problema similar, y tratar de entender de dónde viene es frustrante. Hay un par de cosas que podrían estar causando un problema.

  • Llaman a algo antes de llamar al método InitializeComponent(); ? Anteriormente, tuve un método para llamar a elementos xaml, que todavía no se han inicializado.
  • ¿Ha intentado presionar F10 para iniciar la aplicación, usar Paso a Paso le permitirá ver el proceso exacto de inicio?
  • ¿Has comprobado tu nombre? XAML puede tragar errores como métodos mal escritos, y luego se lanza una excepción en el tiempo de ejecución, esto es particularmente cierto para los proveedores de DataSet. Te sorprenderías de lo que puedes salirte con la tuya.
  • Coger una excepción para abrir un formulario es bastante fundamental, preferiría mirar a los dependientes (enlaces de datos o XAML) y tratar con los primeros.

esperanza los puestos de socorro .......

+0

* no se muestran otros métodos aparte de los indicados en la pregunta. InitializeComponents está solo en el constructor de ambas ventanas. – vidstige

+0

* Buen punto. Supongo que una forma es ejecutar todo el código que pueda arrojarse antes de que se muestre el cuadro de diálogo. – vidstige

1

también reconstruí su respuesta en Visual Studio 2010 en un proyecto en blanco WPF 3.5.

El proyecto se comportó como se esperaba, es decir, Window_Loaded lanzó la excepción y fue capturado por el evento de clic de botón.

Así que no estoy seguro de por qué el suyo no funciona, ¿tal vez intente publicar su App.xml.cs y cualquier otro código que no haya mostrado aquí?

Mientras tanto, pensé que me gustaría señalar algunas cosas:

WPF en efecto, controlar las excepciones no capturadas "" un poco diferente de Windows Forms. Trate de mirar esto por un motor de arranque:

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

Parece como si no hay un equivalente exacto en WPF para el método SetUnhandledExceptionMode (Ver http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413).Pruebe sus consejos sobre cómo registrar un controlador y vea si eso lo ayuda a usted.

Recomendaría recorrer su código - establecer un punto de interrupción en Window_Loaded, y ver qué pasa - prestar mucha atención a la pila de llamadas.

¡Buena suerte!

1

Investigando esto un poco más Encontré esta peculiar entrada de blog que describe un problema similar.

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

Como resulta que puede haber un problema arquitectura de procesador de 64 bits. ¿Quién lo hubiera adivinado? Podría explicar por qué algunas personas no podían reproducir el problema con mi simple ejemplo. Traté de compilar mi ejemplo en "Cualquier CPU", x64 y x86, pero fue en vano. En x64, todo el asunto estalló completamente estrellándose con un cuadro de diálogo de bloqueo de Windows.

Supongo que esta es la respuesta sin verificarlo en una máquina de 32 bits.

2

el "por qué" se explica aquí: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

En resumen, la excepción no puede ser propagado en los sistemas operativos de 64 bits, porque hay una transición entre el modo de núcleo y usuarios.

La prueba de IntPtr.Size en la respuesta @midspace no es adecuada porque IntPtr.Size será igual a 4 en un proceso x86 que se ejecuta en un sistema operativo x64 (debe usar Environment.Is64BitOperatingSystem en lugar de .NET 4 y superior).

La solución ahora: use otro evento como ContentRendered que se llama después del Loaded o ponga su código en el constructor de la ventana.

Nunca use Loaded (o OnLoad en Winforms), porque si hay una excepción allí, no sabe qué puede suceder.

Tener una mirada también en esta respuesta: https://stackoverflow.com/a/4934010/200443

Cuestiones relacionadas