WPF - Validação com IDataErroInfo
Em meu artigo - SilverLight - Fazendo a validação no databinding (C#) eu
mostrei como podemos realizar a validação usando o evento BindingValidationError
em aplicações SilverLight usando a linguagem C#.
No artigo de hoje eu mostro como implementar a validação de
dados usando a interface IDataErrorInfo em
aplicações WPF com C#. Lembrando que este recurso esta
disponível a partir da versão 3.5.
Ao criar aplicações WPF com dados vinculados nunca devemos nos esquecer da importante tarefa de validar a entrada de dados (ou você vai deixar que dados inválidos sejam aceitos ?). A partir da versão 3.5 a WPF oferece um novo suporte a validação de dados fornecido pela interface IDataErrorInfo que pode ser usada para oferecer informações de erros personalizadas.
Você pode utilizar a interface IDataErrorInfo para que o WPF pergunte aos seu objetos de negócio se eles estão em um estado válido ou não. Isso remove a necessidade de colocar a lógica de negócio em objetos separados da camada de negócio e permite que você crie objetos independentes da plataforma da interface do usuário. A interface IDataErrorInfo não é nova ela existe desde os tempos do Windows Forms , e, isso facilita a reutilização de aplicações herdadas do Windows Forms.
A interface IDataErrorInfo fornece a funcionalidade para oferecer a informação de erros personalizados que pode ser vinculados a interface de usuário. Esta interface expõe os seguintes membros:
Nome | Descrição |
Error | Obtem uma mensagem de erro indicando oque esta errado com o objeto |
Item | Obtém a mensagem de erro para a propriedade com o nome fornecido. |
Para realizar a validação com IDataErrorInfo você tem que implementar a propriedade Item colocando a lógica de validação para cada propriedade que o seu modelo de validação exige. Feito isso a próxima etapa e definir a partir do código XAML a propriedade ValidatesOnDataErrors como True e decidir quando você quer que a lógica da validação seja invocada através de UpdateSourceTrigger.
Projeto para Validação com IDataErrorInfo
Vamos criar um projeto WPF usando o Visual Basic 2010 Express Edition no menu File->New Project selecionando o template WPF Application e informando o nome Alunos_Wpf;
Nosso projeto é bem simples: teremos uma interface definida com 1 Button, 3 Label, 3 TextBox onde iremos validar a entrada de dados para o código do aluno, nome do aluno e nota do aluno.
A seguir vemos o leiaute da janela WPF e logo a seguir o código XAML do arquivo MainWindow.xaml;
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Alunos" Height="300" Width="525" xmlns:src="clr-namespace:Alunos.Alunos_Wpf" WindowStartupLocation="CenterScreen"> <Window.Resources> <src:Aluno x:Key="Alunos"></src:Aluno> <!--definindo o estilo da tooltip do erro para o textbox--> <Style x:Key="txterror" TargetType="{x:Type TextBox}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"> </Setter> <Setter Property="Background" Value="LightSalmon"></Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Label Height="28" HorizontalAlignment="Left" Margin="12,27,0,0" Name="label1" VerticalAlignment="Top" Width="151" Content="Código do Aluno" FontSize="14" Foreground="Lime"></Label> <TextBox Height="23" Margin="262,27,96,0" Name="txtCodigo" VerticalAlignment="Top" Style="{StaticResource txterror}"> <TextBox.Text> <Binding Path="Codigo" Source="{StaticResource Alunos}" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule></ExceptionValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <Label Height="28" HorizontalAlignment="Left" Margin="12,72,0,0" Name="label2" VerticalAlignment="Top" Width="151" Content="Nome do Aluno" Foreground="#FF00F300" FontSize="14"></Label> <Label HorizontalAlignment="Left" Margin="12,122,0,112" Name="label3" Width="151" Content="Nota" FontSize="14" Foreground="Lime"></Label> <TextBox Height="23" Margin="262,74,96,0" Name="txtNome" VerticalAlignment="Top" Style="{StaticResource txterror}"> <TextBox.Text> <Binding Path="Nome" Source="{StaticResource Alunos}" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule></ExceptionValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <TextBox Margin="262,127,96,112" Name="txtNota" Style="{StaticResource txterror}"> <TextBox.Text> <Binding Path="Nota" Source="{StaticResource Alunos}" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule></ExceptionValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <Button Height="32" Margin="166,0,197,31" Name="btnEnvia" VerticalAlignment="Bottom" Content="Enviar"></Button> <Grid.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Black" Offset="0" /> <GradientStop Color="#002DAEE1" Offset="0.988" /> </LinearGradientBrush> </Grid.Background> </Grid> </Window> |
Definido o leiaute devemos criar a classe Aluno que será a fonte de dados vinculada via Resources.
No menu Project selecione Add Class e informe o nome Aluno.vb. A seguir defina o seguinte código :
Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.ComponentModel Namespace Alunos_Wpf Public Class Aluno Implements IDataErrorInfo Private _codigo As Integer Public Property Codigo() As Integer Get Return _codigo End Get Set(ByVal value As Integer) _codigo = value End Set End Property Private _nome As String = "" Public Property Nome() As String Get Return _nome End Get Set(ByVal value As String) _nome = value End Set End Property Private _nota As Integer Public Property Nota() As Integer Get Return _nota End Get Set(ByVal value As Integer) _nota = value End Set End Property #Region "IDataErrorInfo Membros" Public ReadOnly Property [Error]() As String Implements IDataErrorInfo.Error Get Return Nothing End Get End Property Default Public ReadOnly Property Item(ByVal fieldName As String) As String Implements IDataErrorInfo.Item Get Dim resultado As String = Nothing 'Validação do Código" If fieldName = "Codigo" Then If Me._codigo < 0 Then resultado = "O código do aluno não pode ser menor que 0" End If End If 'Validação do Nome If fieldName = "Nome" Then If Me._nome = String.Empty Then resultado = "O nome do aluno deve ser informado" Else For Each c As Char In Me._nome If AscW(c) < 65 OrElse AscW(c) > 122 Then 'OrElse (c >= 91 AndAlso c <= 96) Then resultado = "O Nome do aluno não deve conter caracteres especiais" End If Next c End If End If 'Validação da nota" If fieldName = "Nota" Then If Me._nota < 0 Then resultado = "A nota não pode ser menor que zero." End If End If Return resultado End Get End Property #End Region End Class End Namespace |
Neste código temos a definição da classe Aluno que contém as propriedades : Codigo, Nome e Nota;
A classe Aluno implementa a interface IDataErrorInfo e implementa as propriedades Item (somente leitura) e Error.
Na implementação de Item estamos definindo a lógica da validação para os campos Codigo , Nome e Nota.
O código XAML destacamos :
A utilização de Resources para definir a fonte de dados e o estilo da mensagem de erro para o usuário:
<Window.Resources> <src:Aluno x:Key="Alunos"></src:Aluno> <!--definindo o estilo da tooltip do erro para o textbox--> <Style x:Key="txterror" TargetType="{x:Type TextBox}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"> </Setter> <Setter Property="Background" Value="LightSalmon"></Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources> |
Na tag : <src:Aluno
x:Key="Alunos"></src:Aluno>
Estamos definindo a fonte de dados para a vinculação no código
XAML aos controles TextBox.
A seguir temos a definição do estilo que será aplicado para exibir as mensagens de erro.
A seguir temos a declaração das tags XAML para definir cada controle usado na janela.
Abaixo vemos a tag para o campo Codigo onde temos:
O DataErrorValidationRule é regra de validação pré-definida que verifica se há erros que são gerados pela implementação IDataErrorInfo do objeto de origem.
A propriedade UpdateSourceTrigger obtém ou define um valor que determina o quando a fonte de dados vinculada será atualizada.
Os valores possíveis para UpdateSourceTrigger são:
Nome | Descrição |
---|---|
Default | O valor padrão da propriedade da propriedade destino vinculada. O valor padrão para a maioria das propriedades de dependência é PropertyChanged, enquanto a propriedade de texto tem um valor padrão igual a LostFocus; |
PropertyChanged | Atualiza a origem vinculada imediatamente sempre que a propriedade de destino vinculada sofre alteração; |
LostFocus | Atualiza a origem vinculada imediatamente sempre que o elemento de destino vinculado perder o foco; |
Explicit | Atualiza a origem vinculada somente quando for chamada o método UpdateSource; |
Se você definir o valor Explicit para UpdateSourceTrigger deverá chamar o método UpdateSource ou as alterações não serão propagadas de volta a fonte.
O método UpdateSource envia o valor do destino atual vinculado para a propriedade de origem vinculada em vinculações TwoWay ou OneWaySource.
<TextBox Height="23" Margin="262,27,96,0" Name="txtCodigo" VerticalAlignment="Top" Style="{StaticResource txterror}"> <TextBox.Text> <Binding Path="Codigo" Source="{StaticResource Alunos}" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule></ExceptionValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> |
O efeito pretendido é que quando uma regra de validação for violada a cor do controle seja alterada para um tom de vermelho (Salmão-LightSalmon) e uma tooltip seja exibida no controle conforme mostra a figura abaixo:
Acabei de mostrar como realizar validações em aplicações WPF com databinding usando a interface IDataErrorInfo. É claro que o assunto não acabou , pelo contrário, esta apenas começando.
Aguarde em breve mais artigos sobre validação em aplicações WPF.
Pegue o projeto completo aqui: Alunos_Wpf.zip
Eu sei é apenas WPF, mas eu gosto...
Referências: