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
Desde Visual Studio 2015 creamos un nuevo proyecto de tipo Blank UWP
Desde el explorador de soluciones creamos una nueva carpeta llamada Binaries y allí adicionamos los archivos generados al compilar ValidatableBase
- ValidatableBase.dll
- ValidatableBase.pdb
Agregamos como referencias del proyecto la libreria ValidatableBase.dll copiada en la carpeta de la solución
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
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>
Ahora creamos una carpeta Models y allí el modelo, una clase
User
definida cmo se ve a continuación, heredando deValidatableBase
```
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; }
}
```
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.
Ahora que tenemos esto listo, regresemos al
xaml
y dejamos listos elDataContext
, losBinding
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
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
deUser
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.
Le hacemos la misma decoración al campo
email
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 propiosValidationAttribute
, pero para mantenerlo simple adicionaremos un atributoValidateWithCustomHandler
al campoEmail
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); } }
Cramos en la clase
User
el métodoIsValidEmail
y lo marcamos con un atributoValidationCustomHandlerDelegate
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
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(); }
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
vamos al
xaml
y configuramos elBinding
del control que muestra los errores, en el últimoTextBlock
<TextBlock Width="400" Height="100" Text="{Binding Errores}" />
Ahora ejecutamos la aplicación y listo! cada vez que presionemos el botón se realizarán las validaciones.
Eso fue todo, espero sea últil ;)