WPF Data Binding and Validation Rules Best Practices

101

Eu tenho um aplicativo WPF muito simples no qual estou usando vinculação de dados para permitir a edição de alguns objetos CLR personalizados. Agora estou querendo colocar alguma validação de entrada quando o usuário clicar em salvar. No entanto, todos os livros do WPF que li não dedicam realmente nenhum espaço a esse problema. Vejo que você pode criar ValidationRules personalizadas, mas estou me perguntando se isso seria um exagero para minhas necessidades.

Portanto, minha pergunta é a seguinte: há um bom exemplo de aplicativo ou artigo em algum lugar que demonstra as melhores práticas para validar a entrada do usuário no WPF?

Mark Heath
fonte

Respostas:

83

Acho que a nova forma preferida pode ser usar IDataErrorInfo

Leia mais aqui

Rudigrobler
fonte
3
Eu também encontrei o framework Cinch ( cinch.codeplex.com ), que inclui uma demonstração de validação de melhores práticas em WPF + MVVM, e usa IDataErrorInfo
Mark Heath
3
No .NET 4.5, você pode usar INotifyErrorInfo, que permite retornar objetos em vez de apenas strings.
Peter
24

Da documentação de Padrões e Práticas da MS :

Validação de dados e relatório de erros

Seu modelo de visão ou modelo frequentemente precisará realizar a validação de dados e sinalizar quaisquer erros de validação de dados para a visão para que o usuário possa agir para corrigi-los.

O Silverlight e o WPF fornecem suporte para o gerenciamento de erros de validação de dados que ocorrem ao alterar propriedades individuais vinculadas a controles na exibição. Para propriedades únicas que são vinculadas a dados a um controle, o modelo ou modelo de visualização pode sinalizar um erro de validação de dados dentro do configurador de propriedade, rejeitando um valor inválido de entrada e lançando uma exceção. Se a propriedade ValidatesOnExceptions na vinculação de dados for verdadeira, o mecanismo de vinculação de dados no WPF e Silverlight tratará a exceção e exibirá uma indicação visual ao usuário de que há um erro de validação de dados.

No entanto, lançar exceções com propriedades dessa maneira deve ser evitado sempre que possível. Uma abordagem alternativa é implementar as interfaces IDataErrorInfo ou INotifyDataErrorInfo em seu modelo de exibição ou classes de modelo. Essas interfaces permitem que seu modelo de visualização ou modelo execute a validação de dados para um ou mais valores de propriedade e retorne uma mensagem de erro para a visualização para que o usuário possa ser notificado sobre o erro.

A documentação continua explicando como implementar IDataErrorInfo e INotifyDataErrorInfo.

Pat
fonte
3
Fiquei preocupado no início quando vi o lançamento de uma recomendação de exceção. feliz em ver que seguido por "lançar exceções com propriedades desta forma deve ser evitado sempre que possível"
kenwarner 01 de
22
também deve ser observado que alguns muppet da microsoft decidiram não incluir INotifyDataErrorInfo em .net4, mas apenas em silverlight. é uma dor ..
aL3891
5
@ al3891- isso será classificado em .NET 4.5- msdn.microsoft.com/en-us/library/…
RichardOD
@ aL3891 Existe alguma alternativa para o INotifyDataErrorInfo ausente?
AgentKnopf
10

Pessoalmente, estou usando exceções para lidar com a validação. requer as seguintes etapas:

  1. em sua expressão de vinculação de dados, você precisa adicionar "ValidatesOnException = True"
  2. no objeto de dados ao qual está se vinculando, você precisa adicionar o manipulador DependencyPropertyChanged, onde verifica se o novo valor atende às suas condições - se não - restaura o valor antigo do objeto (se necessário) e lança uma exceção.
  3. em seu modelo de controle usado para exibir um valor inválido no controle, você pode acessar a coleção de erros e exibir a mensagem de exceção.

o truque aqui é ligar apenas a objetos que derivam de DependencyObject. a implementação simples de INotifyPropertyChanged não funcionaria - há um bug no framework, que o impede de acessar a coleção de erros.

Greg
fonte
3

Verifique também este artigo . Supostamente, a Microsoft lançou sua Biblioteca Corporativa (v4.0) de seus padrões e práticas onde cobrem o assunto de validação, mas Deus sabe por que eles não incluíram validação para WPF, então a postagem do blog para a qual estou direcionando você explica o que o autor fez para adaptá-lo. Espero que isto ajude!

Murki
fonte
2

Você pode estar interessado no aplicativo de amostra BookLibrary do WPF Application Framework (WAF) . Mostra como usar a validação no WPF e como controlar o botão Salvar quando houver erros de validação.

jbe
fonte
0

Se sua classe de negócio for usada diretamente por sua IU, é preferível usar IDataErrorInfo porque coloca a lógica mais perto de seu proprietário.

Se sua classe de negócios for uma classe stub criada por uma referência a um serviço WCF / XmlWeb, você não pode / não deve usar IDataErrorInfo nem lançar Exception para uso com ExceptionValidationRule. Em vez disso, você pode:

  • Use ValidationRule personalizado.
  • Defina uma classe parcial em seu projeto WPF UI e implementa IDataErrorInfo.
Alex Pollan
fonte
1
Sei que isso é antigo, mas espero que Alex seja capaz de responder. Esta é a conclusão a que cheguei também, mas o problema é que você tem que escrever alguma validação para (por exemplo) uma propriedade "Age" que não poderia ser maior que 100 na ValidationRule e, em seguida, repetir a mesma lógica na interface IDataErrorInfo , que duplica a lógica. Existe alguma maneira de contornar isso?
JFTxJ de
Onde você duplica a lógica? em algum tipo de validação de servidor? Eu acho que pelo seu comentário você está validando com IDataErrorInfo na IU e duplicando a validação no objeto de negócio, não é? Nesse caso, é correto validar em ambos os lados. Os objetos de negócios não podem confiar nas IUs e devem realizar sua própria validação (embora pareça uma duplicação)
Alex Pollan,
Não, a duplicação da lógica de validação está no IDataErrorInfo e na regra de validação personalizada ... Uma vez que a regra de validação personalizada é a única maneira de validar os dados ANTES de serem realmente atualizados para o objeto vinculado, essa validação (a idade deve ser inferior então 100) precisa ser definido no IDataErrorInfo para retornar uma mensagem "por campo", mas também deve ser implementado na regra de validação personalizada. Faz sentido?
JFTxJ