Uma das coisas que mais me frustra ao trabalhar com o desenvolvimento de aplicativos para a Windows Store é quando eu me deparo com alguma limitação grotesca da plataforma. Existem certas funcionalidades que não foram portadas para o WinRT que eu não consigo entender o motivo para elas terem ficado de fora. Uma dessas funcionalidades é a validação de dados.

No WPF nós conseguimos validar a entrada de dados através de ValidationRules ou utilizando a interface IDataErrorInfo. Eu até escrevi um artigo uns tempos atrás sobre validação de dados no WPF onde eu mostro como utilizar esses dois tipos de validação. E no WinRT? Como podemos fazer validações de dados? Pois não podemos! Pelo menos não de forma nativa.

Existem algumas maneiras alternativas de fazer a validação de dados em aplicativos para a Windows Store. Após pesquisar bastante sobre esse assunto eu descobri basicamente quatro maneiras de validarmos dados no WinRT. Devido ao meu tempo limitado para a análise, dessas quatro soluções eu consegui reproduzir somente uma com sucesso em um projeto separado. O foco desse artigo não é detalhar cada uma das alternativas, mas sim, apenas lista-las para que você saiba quais são as suas opções. A ideia é escrever outros artigos no futuro onde cada uma dessas opções seja abordada utilizando o mesmo exemplo de validação.

Opção 1: Jerry Nixon Property<T>

De todas as soluções, essa pareceu ser a mais completa. O grande problema é que ela também pareceu ser, de longe, a mais complexa, além de faltar um passo-a-passo de como integrá-la em um projeto à parte.

Jerry Nixon trabalha na Microsoft como Microsoft Developer Evangelist e escreveu esse artigo falando sobre a sua solução para validação de dados no WinRT. A solução depende de criarmos várias interfaces e classes (IProperty, Property<T>, IModel, ModelBase<T>) e um user control (ErrorControl).

Com essas interfaces e classes criadas (que a ideia seria copiar do projeto dele disponível no CodePlex) temos que mudar o nosso “model” para que cada uma das propriedades não sejam mais tipos simples mas sim instâncias de Property<T>. Em uma versão mais nova o Jerry Nixon alterou a sistemática para que fosse possível manter as propriedades no “model” como tipos simples, mas, isso requer uma certa gambiarra nos getters e setters das propriedades.

O código para implementar a validação é bem simples no final. Veja:

[code language=”csharp”] public Pessoa()
{
this.Validator = e =>
{
if (string.IsNullOrWhiteSpace(Nome.Value))
Nome.Errors.Add("Nome é obrigatório");
if (string.IsNullOrWhiteSpace(Sobrenome.Value))
Sobrenome.Errors.Add("Sobrenome é obrigatório");
if (Idade.Value <= 0 || Idade.Value >= 151)
Idade.Errors.Add("Idade deve estar entre 1 e 150 anos");
};
}
[/code]

O resultado final acaba sendo bem surpreendente.

Mas, na minha humilde opinião, eu acho que a complexidade na implementação não compensa o trabalho. Eu só consegui fazer o exemplo do próprio Jerry Nixon funcionar, ou seja, não consegui extrair as partes necessárias para fazer esse código funcionar em um projeto a parte. Eu acho que para que essa sistemática seja utilizável em larga escala, falta alguém extrair essa implementação em uma biblioteca que seja de fácil uso (e, se possível, preferencialmente hospedada no NuGet).

Opção 2: WinRT XAML Validation

A segunda opção que eu encontrei foi a biblioteca WinRT XAML Validation. Ela trabalha com atributos para adicionar o suporte à validação de dados no WinRT. O atributo implementa o código da validação e então você pode utilizar o mesmo atributo para decorar várias propriedades no seu “model“. Veja um exemplo da implementação de um atributo que faz a verificação se um valor está entre 1 e 150:

[code language=”csharp”] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class ValidateIdadeAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return value is short && ((short)value) >= 1 && ((short)value) <= 150
? ValidationResult.Success
: new ValidationResult("Idade deve estar entre 1 e 150");
}
}
[/code]

É possível combinar mais de um atributo para fazer a validação de uma propriedade. Por exemplo, no código abaixo (retirado da aplicação de exemplo da biblioteca) podemos observar várias validações adicionadas na propriedade “NewBid“:

[code language=”csharp”] [Range(0, double.MaxValue, ErrorMessage = "Value must be greater 0.")] [ValidateGreaterCurrentBid] [ValidateNoBidAbuse] [ValidatePossibleMisentryBid(ValidationLevel = ValidationLevel.Warning)] [ValidateActualCurrentBid(UseInImplicitValidation = false)] public double NewBid
{
get { return this.newBid; }
set { this.SetProperty(ref this.newBid, value); }
}
[/code]

Um ponto a favor dessa opção é que ela já foi extraída para uma biblioteca à parte. Podemos simplesmente adicionar uma referência à ela e começar a utilizá-la. O que não gostei foi que o exemplo escolhido pelo autor é muito complexo e não consegui faze-la funcionar em um projeto mais simples por fora (com o tempo que eu tinha reservado para fazer essa análise).

Seria muito interessante se o autor deixasse o código dessa biblioteca disponível no NuGet para que pudéssemos referencia-la mais facilmente.

Opção 3: Byteflux INotifyDataErrorInfo

Esse foi a solução mais caótica que eu encontrei. Eu nem tinha certeza se deveria compartilha-la nesse artigo, mas, como só estou listando as opções que eu encontrei, resolvi lista-la mesmo assim. Essa opção é basicamente um monte de classes que fazem com que a interface INotifyDataErrorInfo funcione no WinRT. Por razões obvias, não consegui fazer esse exemplo funcionar em um projeto à parte.

Opção 4: WinRT XAML Toolkit FieldValidationExtensions

Essa foi a solução mais simples que eu encontrei e foi a única que eu consegui fazer funcionar com sucesso em um projeto à parte. O WinRT XAML Toolkit, entre outras funcionalidades, implementa várias extensões para os campos do XAML. Uma dessas extensões adiciona o suporte a validações nos campos do XAML. Com as chamadas FieldValidationExtensions podemos adicionar facilmente validações para os campos da nossa aplicação diretamente no XAML.

[code language=”xml”] <TextBox x:Name="Nome"
Header="Nome"
ControlExtensions:FieldValidationExtensions.Format="NonEmpty"
ControlExtensions:FieldValidationExtensions.InvalidBrush="Red"
ControlExtensions:FieldValidationExtensions.NonEmptyErrorMessage="Nome é obrigatório"/>
[/code]

O mais legal dessa opção é que podemos facilmente adicionar essa biblioteca pelo NuGet, assim conseguimos adicioná-la ao nosso projeto e começar a utilizá-la em questão de minutos.

É possível criarmos validações complexas utilizando regular expressions, de forma que consigamos fazer validações que dependam de uma quantidade maior de lógica.

Dentre todas as opções, eu acredito que essa seja a mais indicada caso você queira fazer validações simples nos seus aplicativos para a Windows Store.

Concluindo

Validação de dados no WinRT não é algo trivial de ser implementado. Nesse artigo eu apenas listei quatro soluções que eu encontrei em algum tempo de pesquisa sobre esse assunto. A única solução simples foi a utilização do WinRT XAML Toolkit. Em artigos futuros eu pretendo abordar em detalhes cada uma dessas alternativas. Até lá você pode se aventurar com os links disponibilizados nesse artigo.

Até a próxima!

André Lima