Branch de Referência
Compare validation com navigation
Qualquer aplicativo que aceite entrada de usuários deve garantir que a entrada seja válida. Um aplicativo pode, por exemplo, verificar se a entrada que contém apenas caracteres em um intervalo específico, tem um determinado comprimento ou corresponde a um formato específico. Sem validação, um usuário pode fornecer dados que causam falha no aplicativo. A validação adequada impõe regras de negócio e pode ajudar a impedir que um invasor injete dados maliciosos.
No contexto do padrão Model-View-ViewModel (MVVM), um Model ou ViewModel geralmente será necessário para executar a validação de dados e sinalizar quaisquer erros de validação para a View para que o usuário possa corrigi-los. A imagem abaixo mostra as classes envolvidas no processo de validação.
As propriedades do ViewModel que requerem validação são do tipo ValidatableObject<T>, e cada instância ValidatableObject<T> tem regras de validação adicionadas à sua propriedade Validations. A validação é chamada do ViewModel chamando o método Validate da instância ValidatableObject<T>, que recupera as regras de validação e as executa na propriedade ValidatableObject<T>.Value. Quaisquer erros de validação são colocados na propriedade Errors da instância ValidatableObject<T> e a propriedade IsValid da instância ValidatableObject<T> é atualizada para indicar se a validação foi bem-sucedida ou falhou. O código a seguir mostra a implementação do ValidatableObject<T>:
using CommunityToolkit.Mvvm.ComponentModel;
namespace RMLib.Validations;
public class ValidatableObject<T> : ObservableObject, IValidity
{
private IEnumerable<string> _errors;
private bool _isValid;
private T _value;
public List<IValidationRule<T>> Validations { get; } = new();
public IEnumerable<string> Errors
{
get => _errors;
private set => SetProperty(ref _errors, value);
}
public bool IsValid
{
get => _isValid;
private set => SetProperty(ref _isValid, value);
}
public T Value
{
get => _value;
set => SetProperty(ref _value, value);
}
public ValidatableObject()
{
_isValid = true;
_errors = Enumerable.Empty<string>();
}
public bool Validate()
{
Errors = Validations
?.Where(v => !v.Check(Value))
?.Select(v => v.ValidationMessage)
?.ToArray()
?? Enumerable.Empty<string>();
IsValid = !Errors.Any();
return IsValid;
}
}
A notificação de alteração de propriedade é fornecida pela classe ObservableObject e, portanto, um controle Entry pode se vincular à propriedade IsValid da instância ValidatableObject<T> na classe do ViewModel para ser notificado se os dados inseridos são válidos ou não.
As regras de validação são especificadas criando uma classe que deriva da interface IValidationRule<T>, que é mostrada no exemplo de código a seguir:
public interface IValidationRule<T>
{
string ValidationMessage { get; set; }
bool Check(T value);
}
Essa interface especifica que uma classe de regra de validação deve fornecer um método Check booleano que é usado para executar a validação necessária e uma propriedade ValidationMessage cujo valor é a mensagem de erro de validação que será exibida se a validação falhar.
O exemplo de código a seguir mostra a regra IsNotNullOrEmptyRule<T> de validação, que é usada para realizar a validação do nome de usuário e senha inseridos pelo usuário na RMSLoginPage:
public class IsNotNullOrEmptyRule<T> : IValidationRule<T>
{
public string ValidationMessage { get; set; }
public bool Check(T value) =>
value is string str && !string.IsNullOrWhiteSpace(str);
}
O método Check retorna um booleano indicando se o argumento de valor é nulo, vazio ou consiste apenas em caracteres de espaço em branco.
Às vezes, a validação pode envolver propriedades dependentes. Um exemplo de propriedades dependentes é quando o conjunto de valores válidos para a propriedade A depende do valor específico que foi definido na propriedade B. Verificar se o valor da propriedade A é um dos valores permitidos envolveria a recuperação do valor da propriedade B. Além disso, quando o valor da propriedade B fosse alterado, a propriedade A precisaria ser revalidada.
No aplicativo multiplataforma MinhaQualidadeMaui, as propriedades do ViewModel que requerem validação são declaradas como sendo do tipo ValidatableObject<T>, onde T é o tipo do dado a ser validado. O exemplo de código a seguir mostra um exemplo de duas dessas propriedades:
public ValidatableObject<string> Login { get; private set; }
public ValidatableObject<string> Senha { get; private set; }
Para que a validação ocorra, as regras de validação devem ser adicionadas à coleção Validations de cada instância ValidatableObject<T>, conforme demonstrado no exemplo de código a seguir:
private void AddValidations()
{
Login.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "O campo Usuário é obrigatório." });
Senha.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "O campo Senha é obrigatório." });
}
Este método adiciona a regra de validação IsNotNullOrEmptyRule<T> à coleção Validations de cada instância ValidatableObject<T>, especificando valores para a propriedade ValidationMessage da regra de validação, que especifica a mensagem de erro de validação que será exibida se a validação falhar.
A validação também é acionada automaticamente sempre que uma propriedade vinculada é alterada. Por exemplo, quando uma ligação bidirecional na RMSLoginPage define a propriedade Login ou Senha, a validação é acionada. O exemplo de código a seguir demonstra como isso ocorre:
<framecustom:RMSCustomEntry
x:Name="entryLogin"
...
FontFamily="NunitoSans-Regular.ttf#NunitoSans-Regular" >
<framecustom:RMSCustomEntry.Behaviors>
<mct:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidateCommand}" />
</framecustom:RMSCustomEntry.Behaviors>
</framecustom:RMSCustomEntry>
O controle CustomEntry é vinculado à propriedade Login.Value da instância ValidatableObject<T> e a coleção Behaviors do controle tem uma instância EventToCommandBehavior adicionada a ela. Esse comportamento executa o ValidateCommand em resposta ao disparo do evento TextChanged no CustomEntry, que é gerado quando o texto no CustomEntry é alterado. Por sua vez, o ValidateCommand executa o método OnValidate, que executa o método Validate na instância ValidatableObject<T>. Portanto, toda vez que o usuário insere um caractere no controle CustomEntry para o nome de usuário, é realizada a validação dos dados inseridos.
O aplicativo multiplataforma MinhaQualidadeMaui notifica o usuário sobre quaisquer erros de validação, destacando o controle que contém os dados inválidos com uma borda vermelha e exibindo uma mensagem de erro que informa ao usuário por que os dados são inválidos abaixo do controle que contém os dados inválidos. Quando os dados inválidos são corrigidos, a borda volta ao estado padrão e a mensagem de erro é removida. A imagem abaixo mostra a RMSLoginPage quando há erros de validação.

