André Alves de Lima

Talking about Software Development and more…

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.

12 thoughts on “Validação de dados no WPF

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *