16 04 2011
Validação de dados no WPF
[Atenção!!! Este artigo tem sua versão em vídeo! Se quiser pular a parte escrita e só assistir o vídeo, dê uma olhada no final do post!]
Olá pessoal, tudo certo?
No artigo de hoje vou abordar o fucionamento da validação de dados da interface do usuário no WPF. A validação no WPF é feita utilizando Validation Rules. Elas podem ser do tipo ExceptionValidationRule ou DataErrorValidationRule. Vejamos abaixo a definição desses dois tipos de Validation Rules:
- ExceptionValidationRule: o erro de validação é ativado quando alguma exception for lançada no processo de atualização do binding. É representado no binding através do elemento ValidatesOnExceptions, que deve ser configurado como True para ativar esse tipo de validação;
- DataErrorValidationRule: o erro de validação é ativado por objetos que implementam a interface IDataErrorInfo. É representado no binding através do elemento ValidatesOnDataErrors, que deve ser configurado como True para ativar esse tipo de validação.
Para demonstrar o funcionamento desses tipos de validação, vamos criar uma WPF Application utilizando o Visual Studio 2010 e o .NET Framework 4.
No code-behind da MainWindow, crie uma pequena classe chamada Produto, que posteriormente vai servir de fonte de dados para a nossa demonstração (não esqueçam de acrescentar um using System.ComponentModel devido à utilização da interface INotifyPropertyChanged):
public class Produto : INotifyPropertyChanged { private double precoInicial; public double PrecoInicial { get { return precoInicial; } set { precoInicial = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("PrecoInicial")); } } public event PropertyChangedEventHandler PropertyChanged; }
Vejam que nossa classe tem somente uma propriedade chamada PrecoInicial. Utilizemos agora uma instância dessa classe como fonte de dados que alimentará um TextBox na nossa interface:
Notem os quatro pontos importantes além da definição das linhas / colunas do grid e do TextBlock com o texto “Preço Inicial”:
- 1 – Declaração do namespace do nosso projeto, para conseguirmos visualizar a classe Produto dentro do nosso XAML;
- 2 – Declaração de uma instância da nossa classe Produto como um Static Resource dentro do nosso Grid;
- 3 – Configuração do DataContext do Grid apontando para a nossa instância da classe Produto;
- 4 – Binding da propriedade Text do nosso TextBox apontando para a propriedade PrecoInicial do nosso contexto.
Se rodarmos a aplicação como demonstrado acima, veremos que ela se comporta do modo esperado.
Agora, se simplesmente configurarmos como True o elemento ValidatesOnExceptions do nosso binding, o resultado é que, sempre que uma exception for lançada durante o processo de atualização do binding, um erro de validação será disparado. O mesmo se aplica para o elemento ValidatesOnDataErrors, seguindo os parâmetros que foram informados no início do artigo.
Vamos agora entender como podemos fazer uma ValidationRule customizada. Com a validação que vamos construir, queremos assegurar que o valor informado para a propriedade PrecoInicial será maior que zero. Então, no nosso code-behind, vamos implementar uma classe chamada MaiorQueZeroValidationRule que implementa a interface ValidationRule:
public class MaiorQueZeroValidationRule : ValidationRule { public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { double valorConvertido = 0; if (double.TryParse(value.ToString(), out valorConvertido)) { if (valorConvertido > 0) return ValidationResult.ValidResult; else return new ValidationResult(false, "O valor deve ser maior que zero."); } else return new ValidationResult(false, "O valor deve ser um número."); } }
Vejam que a única função que temos que implementar é a Validate, que deve retornar uma instância de ValidationResult. No caso do valor ser válido, retornamos um ValidationResult.ValidResult. Já no caso do valor ser inválido, retornamos uma nova instância de ValidationResult, informando que o valor não é válido e determinando a mensagem de erro.
Vamos alterar agora a definição do nosso TextBox no XAML para a seguinte:
Ao executarmos a aplicação, notamos que qualquer valor que não seja um número maior que zero resultará em um erro de validação, exatamente como definimos na nossa ValidationRule. Porém, notem que somente um retângulo vermelho é pintado ao redor do controle e nenhuma informação ou mensagem sobre o erro é exibida. Vamos agora verificar como podemos exibir a mensagem com uma ToolTip em caso de algum erro ocorrer no binding.
Para fazermos isso, vamos definir um estilo dentro da seção de Resources do nosso Grid que será aplicado a todos os TextBoxes dentro dele:
Basicamente estamos indicando que a propriedade ToolTip dos TextBoxes serão setadas com o valor de (ValidationErrors)[0].ErrorContent sempre que a propriedade Validation.HasError dos TextBoxes for igual a true.
Executem a aplicação e vejam que a partir desse momento, sempre que um erro for disparado, a ToolTip será exibida:
E se quisermos alterar o template do controle quando ele tiver algum erro? Nesse caso, podemos definir um ControlTemplate que será utilizado como ErrorTemplate no nosso controle. Podemos então definir o seguinte ControlTemplate na seção de Resources do nosso Grid:
Nesse ControlTemplate nós basicamente definimos que iremos exibir um ponto de exclamação em vermelho antes do próprio conteúdo do controle.
Finalmente, precisamos setar o elemento Validation.ErrorTemplate do nosso TextBox apontando para esse ControlTemplate:
Pronto! Ao executarmos nossa aplicação e causarmos um erro no binding, veremos que o nosso controle é exibido da seguinte forma:
Para finalizar, vamos ver como é que funciona a questão das DataErrorValidationRules. Quando setamos o elemento ValidatesOnDataError ou criamos uma DataErrorValidationRule dentro do nosso binding, o objeto que servirá de fonte de dados no binding deve implementar a interface IDataErrorInfo. Façamos então essa implementação na nossa classe Produto:
public class Produto : INotifyPropertyChanged, IDataErrorInfo { private double precoInicial; public double PrecoInicial { get { return precoInicial; } set { precoInicial = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("PrecoInicial")); } } public event PropertyChangedEventHandler PropertyChanged; public string Error { get { throw new NotImplementedException(); } } public string this[string columnName] { get { string retorno = string.Empty; if ((columnName.Equals("PrecoInicial")) && (precoInicial <= 0)) retorno = "Preço Inicial deve ser maior que zero."; return retorno; } } }
Vejam que a única coisa que precisamos implementar é a propriedade indexada this[string columnName], que será disparada sempre que um valor for setado nas propriedades da classe Produto. Dentro dessa propriedade indexada devemos ver se a coluna sendo setada possui algum erro e, caso positivo, precisamos retornar qual é a mensagem de erro desejada.
Feito isso, precisamos somente alterar o binding do nosso TextBox, indicando um DataErrorValidationRule, ao invés da nossa Validation Rule customizada:
Execute a aplicação e veja que ela se comporta como planejado.
E com isso termino por aqui mais um artigo relacionado ao Data Bindingo do WPF. Espero que vocês tenham gostado!
Para assistir a versão em vídeo desse artigo, cliquem aqui.
Até a próxima!
André Alves de Lima.
Trabalhando com Value Converters no WPF Revisão das metas Jul/2011 e novidades pessoais
[…] LINK PARA O POST ORIGINAL AQUI! […]
[…] ATENÇÃO!!! ESTE BLOG MUDOU DE ENDEREÇO: http://www.andrealveslima.com.br VISITE ESTE MESMO POST NO NOVO ENDEREÇO AQUI […]
Opa Andre, bom tutorial, mas fiquei com uma dúvida no final, mesmo vc trocando para DataErrorValidationRule , eu notei que o TryParse continua a ser testado (como mostrado no vídeo), como pode isso? Pergunto isto porque vc removeu ao final o binding o que não meu entender não faria mais o tryparse ser executado.. ou não?….
André desconsidere a minha pergunta anterior, agora entendi, a mensagem veio em Inglês e não pt, sinal que a validação foi feita internamente e jogada via excepction no tooltip… No mais, obrigado e valeu!!!!
Para mim, não abre o vídeo…
Olá Guilherme!
Primeiramente, obrigado pelo comentário.
Dei uma olhada e parece que o link está realmente quebrado. Como o vídeo esta armazenado no portal da MSDN, entrei em contato com a pessoa responsável na Microsoft para que o problema seja resolvido. Todos os links para vídeos de WPF no portal MSDN nao estao abrindo. Enfim, assim que tiver uma posicao eu volto a postar aqui. E, caso eu nao tenha uma resposta nos próximos dias, eu reposto o vídeo no Youtube e acerto o link.
Obrigado por ter me falado sobre esse problema. De outra forma eu nunca saberia que o link estava quebrado.
Grande abraco,
André Lima
por acaso o link do vídeo está disponível em algum outro local?
Olá Alan, você pode baixar os vídeos no seguinte link:
https://skydrive.live.com/redir?resid=3E33BD927B1E5D27!4822&authkey=!ANmRAtTvDvcMPBs
Abraco!
André Lima
[…] para manter a formatação do código-fonte, eu já cheguei a postar código em forma de imagem (veja um exemplo aqui). Não preciso nem dizer que essa é uma péssima opção, porque se o leitor quiser copiar o […]
[…] 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 […]
O link do video está quebrado. Não abre. Poderia verificar, por favor?
Olá Frederico!
Obrigado por me atentar para este detalhe do link quebrado.. Procurei aqui no meu computador e estranhamente não consegui encontrar o vídeo correspondente a este artigo.. Porém, eu gravei uma série sobre WPF para o portal MSDN e em um dos capítulos eu falei exatamente sobre esse mesmo tema:
https://msdn.microsoft.com/pt-br/vstudio/gg663648
Inclusive, essa série conta com vários vídeos (meus e de outras pessoas), todos sobre a certificação para WPF que existia antigamente.. Vale a pena dar uma olhada na lista completa:
https://msdn.microsoft.com/pt-br/vstudio/gg675937
Abraço!
André Lima
E se quiser validar os dados quando o botão cadastrar for clicado ?
Olá Leo, obrigado pelo comentário!
Veja se o conteúdo desta thread do StackOverflow te ajuda:
Validation on button click event wpf c#
Abraço!
André Lima
Olá, Obrigado pela resposta, mas esse link não me ajudou muito n, mas estou conseguindo de outra forma, pq eu quero fazer a junção dessas duas formas de validação diretamente no campo, mas tb quando o usuário clicar no botão e ainda com uma MessageBox listados todos os erros encontrados pq meus formulários tem 2, 3 TabItems organizadas na tabcontrol.. e no final cadastrar… Na vida real a usabilidade do cliente exige uma junção de coisas… heee….
Olá Leo!
Que pena.. Você já está perto de conseguir o que você está querendo? Ou ainda falta bastante? Se você puder compartilhar como está o seu código no momento, talvez eu consiga ajudar de alguma maneira..
De qualquer forma, se você conseguir resolver essa sua demanda, volte aqui depois e compartilha com a gente o resultado final, OK?
Abraço!
André Lima
[…] 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 […]