jueves, 18 de octubre de 2007

Validation Application Block, composite validators inútiles

No trabajo mucho con winform y como para compensar tengo que hacer una aplicación con 300 text box más o menos todos con validación, etc. La aplicación tiene que permitir al usuario ingresar muchos datos, ahora, no todos junto, el usuario puede poner algunos datos, guardarlos y luego continuar, como paso final genera un archivo de salida que se integra a un sistema, muy bonito...para el usuario.
 Lo que me hacía falta era la forma de validar ciertas cosas, por decir, un campo "edad" numérico, pero sólo si tiene un valor, por supuesto que para validar que sea numérico utilizo TypeConversionValidator, perfecto, el problema es que no puedo lanzar la validación si el campo no se encuentra lleno porque tira una fea excepción. Entonces dije "es una excelente ocasión para utilizar los composite validator, and y or" en teoría nos permiten aplicar validaciones convinadas, pero de un modo extraño.

¿Que esperamos de los composite validator?

Del AndComposite uno esperaría que un AND funcione del siguiente modo: si pongo dentro dos reglas de validación que el total sea válido sólo si ambas lo son, es más, para ser fino podemos hacerlo "lazzy" es decir, que si detecta que la primer regla no es válida que no continúe, esto hubiera sido genial para poner un string lenght validator y luego un type conversion para que si el primero no es válido no continúe y no "pinche", pero no, no funciona así, remitamonos al código del método DoValidate

protected internal override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults)
{
    foreach (Validator validator in this.validators)
    {
        validator.DoValidate(objectToValidate, currentTarget, key, validationResults);
    }
}

 
Parece que no nos soluciona el problema, el tipo sigue adelante a pesar que la primer regla no pase, me pregunto ¿para qué sirve entonces?¿No es lo mismo que poner varios validadores sueltos?

Segundo intento OrCompositeValidator

Siguiendo con nuestra preciada inocencia imaginamos que el OCV nos dirá que algo es válido si alguna de sus reglas lo es, por lo tanto podemos poner un string lenght negado para que sólo continúe en caso contrario, pero no, otra vez la implementación no nos ayuda

protected internal override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults)
{
    List<ValidationResult> nestedValidationResults = new List<ValidationResult>();
    foreach (Validator validator in this.validators)
    {
        ValidationResults results = new ValidationResults();
        validator.DoValidate(objectToValidate, currentTarget, key, results);
        if (results.IsValid)
        {
            return;
        }
        nestedValidationResults.AddRange(results);
    }
    base.LogValidationResult(validationResults, this.GetMessage(objectToValidate, key), currentTarget, key, nestedValidationResults);
}

 
Lo que hace es salir en cuanto alguna regla sea válida, o sea es "lazzy" lo contrario del And, por lo tanto no nos sirve porque además si la regla no es válida agrega el error al ValidationResult, es decir, si la primer regla dentro del OCV no es válida continúa (esto es correcto) pero ¡agrega el error al resultado! por más que la segunda sea válida, con lo cual no sirve para nada tampoco.

En resumen ninguno de los dos sirven para nada, si alguien puede sacarles provecho que me avise.....

La solución

La solución fue....un range validator, un valor por defecto y evitar que se ingresen datos que no sean numéricos en dichos TextBox, eso lo hice de un modo más o menos elegante.

public void AssignNroHandler(TextBox txt)
{
  txt.KeyPress += HandleNro;
}

public void HandleNro(object sender, KeyPressEventArgs e)
{
 short nro = 0;
 e.Handled = !short.TryParse(Convert.ToString(e.KeyChar), out nro);
}

Después por cada TextBox que quiero evitar que se ingresen datos que no sean numéricos hago

this.AssignNroHandler(this.textBox1);

Y santo remedio, en fin.