En una ocasión estando desarrollando un proyecto en WPF con varios desarrolladores más, surgió la pregunta ¿Cómo manejar las excepciones en WPF? Y es que esta pregunta puede parecer sencilla, ya que como todos sabemos en .NET existe el manejo de excepciones a través de la estructura try … catch … finally. Sin embargo, cuando se esta trabajando en el UI de un proyecto en WPF y varios desarrolladores hacen y modifican eventos y procedimientos en las pantallas – validación, llamadas a lógica de negocios y manejo de errores – es importante saber como va a reaccionar la aplicación a errores no esperados en secciones de código en donde no se han programado bloques de control de errores. En otras palabras lo que se busca es una forma central de manejar las excepciones, tal y como se logra hacer de manera sencilla en ASP.NET cuando en el archivo web.config le indicamos a la aplicación que en caso de un error no previsto y no atrapado, despliegue el error en una página específica. Durante esta experiencia investigué cuál era el modo más cercano de lograr este comportamiento en WPF y este post el resultado de esta investigación.
En primera instancia, si existe un lugar central desde donde crear un método que nos permita manejar los errores que se disparen en la aplicación WPF y que no hayan sido manejados por bloques de try…catch previamente. Este lugar es en el archivo App.xaml.cs – en el caso de C#. En esta clase podemos definir un manejador de eventos para el evento de aplicación DispatcherUnhandledException el cual se va a disparar cada vez que ocurre un evento inesperado. A continuación el código de la clase App.
using System.Windows.Threading;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
string errorMessage = string.Format("Ocurrió una excepción inesperada. {0}{1}"
, Environment.NewLine, e.Exception);
MessageBox.Show(errorMessage, "Error atrapado en el obj Application");
e.Handled = true;
}
}
En este caso vamos a necesitar agregar el namespace using System.Windows.Threading que es el namespace donde se encuentra declarado el tipo DispatcherUnhandledExceptionEventArgs el cual es el que vamos a utilizar como parámetro para manejar el error. Esta variable – e en nuestro caso – contiene una referencia a la excepción que no ha sido manejada y una bandera indicando si la excepción ha sido manejada o no. Es importante destacar que este evento se va a disparar solamente en el thread del UI, otras excepciones lanzadas desde otro thread no van a ser atrapadas – lo veremos en el ejemplo. En el archivo App.xaml, vamos a agregar el evento y su correspondiente manejador, el cual en nuestro caso es App_DispatcherUnhandledException.
Seguidamente procedemos a agregar el código correspondiente en WPF y XAML. Primeramente vamos a agregar 3 botones, el primero de ellos no va a manejar la excepción y por lo tanto debe de ser atrapada en el manejador global de errores, el segundo de ellos atrapa la excepción localmente ya que tiene un bloque try … catch y el último lanza una excepción en otro thread, por lo tanto no es manejada en nuestro evento de manejo de errores global a la aplicación. El código en cs es el siguiente.
private void btnGuardar_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
try
{
throw new NotImplementedException();
}
catch (NotImplementedException ex)
{
MessageBox.Show(ex.Message, "Error manejado en la ventana");
}
}
private void button2_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
throw new NotImplementedException();
};
worker.RunWorkerAsync();
}
Del lado de XAML, agregamos los 3 botones que van a disparar los eventos anteriores.
La pantalla en modo gráfico luce así:
Al ejecutar el primer botón – el error se maneja en el App.xaml.cs - el resultado es el siguiente:
Al utilizar el botón en donde se maneja el error localmente el resultado es el siguiente:
Por último, al lanzar una excepción en otro thread no se dispara ningún error y este no se maneja de forma global.
De esta manera podemos manejar de manera unificada las excepciones sin manejar en aplicaciones WPF.
No hay comentarios:
Publicar un comentario