UWP - Cómo implementar validación de campos en Universal Apps

Avanzado

Actualmente UWP no incorpora ningún framework de validación, sin embargo la comunidad de C# es pujante y en GitHub ya hay una alternativa muy interesante que vale la pena revisar: ValidatableBase .

En este post revisaremos como implmentar validación con atributos utilizando esta libreria.

Tarea 0 - Instalación

Lo primero es que debes descargar o clonar el repositorio de GitHub ya que actualmente al menos no tienen binarios publicados. Abres la solución y la compilas en modo release para obtener la dll.

Tarea 1 - Preparar la solución UWP y agregar la libreria de validación

  1. Desde Visual Studio 2015 creamos un nuevo proyecto de tipo Blank UWP
    Nuevo proyecto UWP

  2. Desde el explorador de soluciones creamos una nueva carpeta llamada Binaries y allí adicionamos los archivos generados al compilar ValidatableBase
    Agregar libreria

    • ValidatableBase.dll
    • ValidatableBase.pdb
  3. Agregamos como referencias del proyecto la libreria ValidatableBase.dll copiada en la carpeta de la solución

  4. Ahora creamos otro folder y lo nombraremos util, allí crearemos BindableBase, sino sabes que es puedes referirte a este artículo : Apps, Binding, INotifyPropertyChanged y BindableBase | XAML | C# , pero en todo caso acá lo tienes

  5. Abrimos el archivo MainPage.xaml y nos aseguramos de insertar este xaml en el Grid que viene por defecto.

    
    
        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Nombre: "/>
                <TextBox Width="250" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Email: "/>
                <TextBox Width="250"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Errores :"/>
                <TextBlock Width="400" Height="100"/>
            </StackPanel>
            <Button HorizontalAlignment="Stretch">Validar</Button>
        </StackPanel>
    
  6. Ahora creamos una carpeta Models y allí el modelo, una clase User definida cmo se ve a continuación, heredando de ValidatableBase

    ```
    using Sullinger.ValidatableBase.Models;

     public class User
    {
        BindableBase binder;
    
    
    private string name;
    
    
    public string Name
    {
        get { return name; }
        set { binder.SetProperty(ref name, value); }
    }
    
    
    private string email;
    
    
    public string Email
    {
        get { return email; }
        set { binder.SetProperty(ref email, value); }
    }
    
    
    public User()
    {
        binder = new BindableBase();
        email = name = string.Empty;            
    }
    

    }

    ```

  7. En la solución creamos una carpeta ViewModels y en ella creamos la clase MainPageVM, por el momento como se ve a continuación

    ```
    public class MainPageVM : BindableBase, ICommand
    {
    public event EventHandler CanExecuteChanged;

     public bool CanExecute(object parameter)
    {
        return true;
    }
    
    
    public void Execute(object parameter)
    {
        throw new NotImplementedException();
    }
    
    
    private User usuario;
    public User Usuario
    {
        get { return usuario; }
        set { SetProperty(ref usuario, value); }
    }
    
    
    private string errores;
    
    
    public string Errores
    {
        get { return errores; }
        set
        { SetProperty(ref errores, value); }
    }
    
    
    public MainPageVM()
    {
        errores = string.Empty;
        usuario = new User();
    }        
    

    }
    ```

    La libreria incorpora mecanismos más sofisticados y útiles que el que vamos a usar para mostrar los errores, pero con el fin de mantenerlo sencillo he optado por cumular los errores en una cadena de texto.

  8. Ahora que tenemos esto listo, regresemos al xaml y dejamos listos el DataContext, los Binding y el Comando del botón, quedando así:

    ```

     <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Nombre: "/>
                <TextBox Width="250" Text="{Binding Usuario.Name, Mode=TwoWay}" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Email: "/>
                <TextBox Width="250" Text="{Binding Usuario.Email, Mode=TwoWay}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Errores :"/>
                <TextBlock Width="400" Height="100"/>
            </StackPanel>
            <Button HorizontalAlignment="Stretch" Command="{Binding}">
                Validar
            </Button>
        </StackPanel>
    </Grid>
    

    ```

Tarea 2 - El proceso de validación

  1. La validación en ValidatableBase es basada en atributos, así que hay que decorar el modelo con atributos que indiquen que queremos validar, la propiedad Name de User la validaremos como requerida.

    [ValidateObjectHasValue( FailureMessage = "El nombre no se puede dejar en blanco", ValidationMessageType = typeof(ValidationErrorMessage))] public string Name { get { return name; } set { binder.SetProperty(ref name, value); } }

    Notemos que el atributo indica que el campo es requerido, y podemos colocar un mensaje de validación personalizado, de igual forma debemos indicar que esta validación es tipo error, podría tambien ser un warning.

  2. Le hacemos la misma decoración al campo email

  3. El campo email debe etener una validación adicional, pues desde luego queremos validar que si corresponda con un correo electrónico válido, hay varias formas de hacerlo con la libreria, ya que incluso puedes crear tus propios ValidationAttribute, pero para mantenerlo simple adicionaremos un atributo ValidateWithCustomHandler al campo Email quedando así

    [ValidateWithCustomHandler( DelegateName = "IsValidEmail", FailureMessage = "Esto no parece un correo electrónico", ValidationMessageType = typeof(ValidationWarningMessage))] [ValidateObjectHasValue(FailureMessage = "El email no se puede dejar en blanco", ValidationMessageType = typeof(ValidationErrorMessage))] public string Email { get { return email; } set { binder.SetProperty(ref email, value); } }

  4. Cramos en la clase User el método IsValidEmail y lo marcamos con un atributo ValidationCustomHandlerDelegate como se ve a continuación

    [ValidationCustomHandlerDelegate(DelegateName = "IsValidEmail")] private IValidationMessage IsValidEmail(IValidationMessage failureMessage, PropertyInfo property) { const string regExp = @"\A(?:[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:.[a-z0-9!#$%&' +/=?^_`{|}~-]+) @(?:a-z0-9?.)+a-z0-9?)\Z";

         return Regex.IsMatch(this.Email, regExp, RegexOptions.IgnoreCase)
            ? null
            : failureMessage;
    }    
    

    ```

Tarea 3 - Mostrar los errores

  1. La aplicación ya esta preparada para realizar las validaciones, invocaremos la validación en el método Execute del viewmodel: MainPageVM
    public void Execute(object parameter) { Usuario.ValidateAll(); }

  2. Así como esta ya se ejecutarán las validaciones, pero desde luego hace falta mostrar los mensajes en pantalla, para ello modificams el código del método Execute del viewmodel: MainPageVM para concatenar todos los mensajes encontrados para cada propiedad tras la validación.

    ```
    public void Execute(object parameter)
    {
    Errores = string.Empty;
    Usuario.ValidateAll();

     if (Usuario.HasValidationMessages())
    {
        var propiedades = Usuario.GetValidationMessages();
    
    
    foreach (var propiedad in propiedades)
    {
        foreach (var error in propiedad.Value)
        {
            Errores += $"{propiedad.Key}: {error.Message}\n";
        }
    }
    

    }

    }
    ```

    Como lo mencioné, la libreria tiene otras cosas más sofisticadas para mostrar los errores a traves de binding de colecciones, pero para mantener el ejemplo sencillo lo he hecho de esta manera

  3. vamos al xaml y configuramos el Binding del control que muestra los errores, en el último TextBlock

    <TextBlock Width="400" Height="100" Text="{Binding Errores}" />

  4. Ahora ejecutamos la aplicación y listo! cada vez que presionemos el botón se realizarán las validaciones.
    Validaciones

Eso fue todo, espero sea últil ;)