[WINFORMS]Uso de DataAnnotations y Validación de Atributos en Winfoms

Introducción

Es algo muy común en aplicaciones WEB, ver que cuando el usuario introduce valores en un formulario y pulsa aceptar, si ha introducido algún valor erróneo, le aparezcan los errores y los mensajes de error.

Normalmente, esto se realiza a través de decorar con atributos las propiedades de nuestras entidades de negocio, por ejemplo:

   1: public class Empleado

   2: {

   3:     [Required(ErrorMessage = "El nombre es un campo obligatorio.")]

   4:     [StringLength(100,ErrorMessage="La longitud máxima permitida es de 100 caracteres.")]

   5:     public string Nombre { get; set; }

   6: }

 

En el ejemplo, si en el formulario no se mete, valor en el campo nombre o se introduce un nombre superior a 100 letras, al pulsar sobre el botón “Enviar” (Por ejemplo), se volvería a cargar el formulario con el errores por el Parámetro ErrorMessage del atributo.

El conjunto de atributos de validación se encuentra en el espacio de nombres “System.ComponentModel.DataAnnotations”, que para poder utilizarlo en una aplicación WINFORMS, es necesario, agregarlo como referencia al proyecto.

Ejemplo

Para comenzar voy a definir 2 interfaces en las que voy a basar el ejemplo.

La primera la interfaz IValidable, la cual va a ser implementada por todas mis entidades:

   1: public interface IValidable

   2: {

   3:     bool IsValid { get; set; }

   4:     List<ValidationResult> ValidationErrors { get; set; }

   5: }

La segunda la interfaz IValidator, que va a definir el contrato de los posibles validadores de objetos:

   1: interface IValidator

   2:    {

   3:         Tuple<bool, List<ValidationResult>> ValidateObject(IValidable objToValidate);

   4:    }

Esta interfaz presenta un método estático que va a recibir un objeto que implemente la Interfaz IValidable y va a devolver un Tuple con valor booleano y una lista de ValidationResult.

A continuación vamos a ver un ejemplo de implementación de la interfaz IValidator (Utilizando un patrón Singleton):

   1: public sealed class Validator : IValidator

   2:     {

   3:         private Validator()

   4:         {

   5:  

   6:         }

   7:         private static Validator validator = new Validator();

   8:  

   9:         public static Tuple<bool, List<ValidationResult>> Validate(IValidable objToValidate)

  10:         {

  11:             if (validator==null)

  12:                 validator = new Validator();

  13:             return validator.ValidateObject(objToValidate);

  14:         }

  15:        

  16:         private Tuple<bool,List<ValidationResult>> ValidateObject(IValidable  objToValidate)

  17:         {

  18:            var results = new List<ValidationResult>();

  19:            var context = new ValidationContext(objToValidate,null,null);

  20:             var obj = System.ComponentModel.DataAnnotations.Validator.TryValidateObject(objToValidate, context, results, true);

  21:   

  22:             return new Tuple<bool,List<ValidationResult>>(obj,results);

  23:         }

  24:        

  25:     }

En el método ValidateObject, vamos a utilizar un objeto de tipo ValidationContext, para definir el contexto de validación de nuestro objeto IValidable, y a través del método TryValidateObject, vamos a obtener si existen o no errores y el listado de errores (si existen) que se han producido, para devolverlos al objeto que realiza la llamada.

Ahora vamos a ver una implementación de la interfaz IValidable:

   1: public class Empleado : IValidable 

   2:     {

   3:         [Required(ErrorMessage = "El nombre es un campo obligatorio.")]

   4:         [StringLength(100,ErrorMessage="La longitud máxima permitida es de 100 caracteres.")]

   5:         public string Nombre { get; set; }

   6:         #region Miembros de IValidable

   7:  

   8:         public bool IsValid

   9:         {

  10:             get {

  11:                 var validator = Validator.Validate(this);

  12:                 _ValidationErrors = validator.Item2;

  13:                 return validator.Item1;

  14:             }

  15:         }

  16:         private List<ValidationResult> _ValidationErrors;

  17:         public List<ValidationResult> ValidationErrors

  18:         {

  19:             get

  20:             {

  21:                 return _ValidationErrors;

  22:             }

  23:             private set

  24:             {

  25:                 _ValidationErrors = value;

  26:             }

  27:         }

  28:  

  29:         #endregion

  30:     }

Dentro de la propiedad IsValid, he introducido la invocación al objeto Validator para hacer las pertinentes validaciones y obtener el conjunto de errores en el caso de existir alguno.

Para ver un ejemplo de utilización:

   1: Empleado empleado = new Empleado();//Fallará

   2: if (!empleado.IsValid)

   3: {

   4:     foreach (var error in empleado.ValidationErrors)

   5:     {

   6:         MessageBox.Show(error.ErrorMessage);

   7:     }

   8: }

   9: Empleado empleadoOK = new Empleado { Nombre = "Javier" };//No falllará

  10: if (!empleadoOK.IsValid)

  11: {

  12:     foreach (var error in empleadoOK.ValidationErrors)

  13:     {

  14:         MessageBox.Show(error.ErrorMessage);

  15:     }

  16: }

  17: else

  18: {

  19:     MessageBox.Show("El empleado es válido.");

  20: }

NOTA: Existe una interfaz IValidatableObject que presenta un método Validate que realiza una función similar, pero he decido crear mi propia interfaz para establecer la propiedad IsValid.

Espero que os sea interesante y/o de utilidad.

 

Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *