Convalida
Suggerimento
Questo contenuto è un estratto dell'eBook, Enterprise Application Patterns Using .NETMAUI, disponibile in .NET Docs o come PDF scaricabile gratuitamente che può essere letto offline.
Qualsiasi app che accetta input dagli utenti deve assicurarsi che l'input sia valido. Un'app può, ad esempio, verificare la presenza di input che contiene solo caratteri in un intervallo specifico, è di una determinata lunghezza o corrisponde a un formato specifico. Senza convalida, un utente può fornire dati che causano l'esito negativo dell'app. La convalida corretta applica regole business e può aiutare a impedire a un utente malintenzionato di inserire dati dannosi.
Nel contesto del modello Model-View-ViewModel (MVVM), è spesso necessario un modello di visualizzazione o un modello per eseguire la convalida dei dati e segnalare eventuali errori di convalida alla visualizzazione in modo che l'utente possa correggerli. L'app multipiattaforma eShop esegue la convalida sincrona lato client delle proprietà del modello di visualizzazione e notifica all'utente di eventuali errori di convalida evidenziando il controllo che contiene i dati non validi e visualizzando messaggi di errore che informano l'utente del motivo per cui i dati non sono validi. L'immagine seguente mostra le classi coinvolte nell'esecuzione della convalida nell'app multipiattaforma eShop.
Visualizzare le proprietà del modello che richiedono la convalida sono di tipo ValidatableObject<T>
e ogni istanza di ValidatableObject<T>
ha regole di convalida aggiunte alla relativa proprietà Validations
. La convalida viene richiamata dal modello di visualizzazione chiamando il metodo Validate
dell'istanza di ValidatableObject<T>
, che recupera le regole di convalida e le esegue sulla proprietà ValidatableObject<T>.Value
. Eventuali errori di convalida vengono inseriti nella proprietà Errors
dell'istanza di ValidatableObject<T>
e la proprietà IsValid
dell'istanza di ValidatableObject<T>
viene aggiornata per indicare se la convalida ha avuto esito positivo o negativo. Il codice seguente illustra l'implementazione del ValidatableObject<T>
:
using CommunityToolkit.Mvvm.ComponentModel;
namespace eShop.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;
}
}
La notifica di modifica delle proprietà viene fornita dalla classe ObservableObject
e pertanto un controllo Entry
può essere associato alla proprietà IsValid
dell'istanza di ValidatableObject<T>
nella classe del modello di visualizzazione per ricevere una notifica relativa alla validità o meno dei dati immessi.
Specifica delle regole di convalida
Le regole di convalida vengono specificate creando una classe che deriva dall'interfaccia IValidationRule<T>
, illustrata nell'esempio di codice seguente:
public interface IValidationRule<T>
{
string ValidationMessage { get; set; }
bool Check(T value);
}
Questa interfaccia specifica che una classe di regole di convalida deve fornire un metodo booleano Check
utilizzato per eseguire la convalida richiesta e una proprietà ValidationMessage
il cui valore è il messaggio di errore di convalida che verrà visualizzato se la convalida non riesce.
L'esempio di codice seguente mostra la IsNotNullOrEmptyRule<T>
regola di convalida, usata per eseguire la convalida del nome utente e della password immessi dall'utente in LoginView
quando si usano servizi fittizi nell'app multipiattaforma eShop:
public class IsNotNullOrEmptyRule<T> : IValidationRule<T>
{
public string ValidationMessage { get; set; }
public bool Check(T value) =>
value is string str && !string.IsNullOrWhiteSpace(str);
}
Il metodo Check
restituisce un valore booleano che indica se l'argomento value è null, vuoto o è costituito solo da spazi vuoti.
Anche se non usato dall'app multipiattaforma eShop, l'esempio di codice seguente mostra una regola di convalida per la convalida degli indirizzi di posta elettronica:
public class EmailRule<T> : IValidationRule<T>
{
private readonly Regex _regex = new(@"^([w.-]+)@([w-]+)((.(w){2,3})+)$");
public string ValidationMessage { get; set; }
public bool Check(T value) =>
value is string str && _regex.IsMatch(str);
}
Il metodo Check
restituisce un valore booleano che indica se l'argomento value è un indirizzo di posta elettronica valido. A tale scopo, cercare l'argomento valore per la prima occorrenza del criterio di espressione regolare specificato nel costruttore Regex
. Se il criterio di espressione regolare è stato trovato nella stringa di input può essere determinato controllando il value
rispetto a Regex.IsMatch.
Nota
La convalida delle proprietà può talvolta comportare proprietà dipendenti. Un esempio di proprietà dipendenti è quando il set di valori validi per la proprietà A dipende dal valore specifico impostato nella proprietà B. Per verificare che il valore della proprietà A sia uno dei valori consentiti comporta il recupero del valore della proprietà B. Inoltre, quando il valore della proprietà B cambia, la proprietà A deve essere riconvalidata.
Aggiunta di regole di convalida a una proprietà
Nell'app multipiattaforma eShop visualizzare le proprietà del modello che richiedono la convalida vengono dichiarate come di tipo ValidatableObject<T>
, dove T
è il tipo dei dati da convalidare. Nell'esempio di codice seguente viene illustrato un esempio di due proprietà di questo tipo:
public ValidatableObject<string> UserName { get; private set; }
public ValidatableObject<string> Password { get; private set; }
Per la convalida, è necessario aggiungere regole di convalida alla raccolta Validations di ogni istanza di ValidatableObject<T>
, come illustrato nell'esempio di codice seguente:
private void AddValidations()
{
UserName.Validations.Add(new IsNotNullOrEmptyRule<string>
{
ValidationMessage = "A username is required."
});
Password.Validations.Add(new IsNotNullOrEmptyRule<string>
{
ValidationMessage = "A password is required."
});
}
Questo metodo aggiunge la regola di convalida IsNotNullOrEmptyRule<T>
all'insieme Validations
di ogni istanza di ValidatableObject<T>
, specificando i valori per la proprietà ValidationMessage
della regola di convalida, che specifica il messaggio di errore di convalida che verrà visualizzato se la convalida non riesce.
Attivazione della convalida
L'approccio di convalida usato nell'app multipiattaforma eShop può attivare manualmente la convalida di una proprietà e attivare automaticamente la convalida quando viene modificata una proprietà.
Attivazione manuale della convalida
La convalida può essere attivata manualmente per una proprietà del modello di visualizzazione. Ad esempio, questo si verifica nell'app multipiattaforma eShop quando l'utente tocca il Login
pulsante su LoginView
, quando si usano servizi fittizi. Il delegato del comando chiama il metodo MockSignInAsync
in LoginViewModel
, che richiama la convalida eseguendo il metodo Validate
, illustrato nell'esempio di codice seguente:
private bool Validate()
{
bool isValidUser = ValidateUserName();
bool isValidPassword = ValidatePassword();
return isValidUser && isValidPassword;
}
private bool ValidateUserName()
{
return _userName.Validate();
}
private bool ValidatePassword()
{
return _password.Validate();
}
Il metodo Validate
esegue la convalida del nome utente e della password immessi dall'utente in LoginView
, richiamando il metodo Validate
in ogni istanza di ValidatableObject<T>
. Nell'esempio di codice seguente viene illustrato il metodo Validate
della classe ValidatableObject<T>
:
public bool Validate()
{
Errors = _validations
?.Where(v => !v.Check(Value))
?.Select(v => v.ValidationMessage)
?.ToArray()
?? Enumerable.Empty<string>();
IsValid = !Errors.Any();
return IsValid;
}
Questo metodo recupera tutte le regole di convalida aggiunte alla raccolta dell'oggetto Validations
. Viene eseguito il metodo Check
per ogni regola di convalida recuperata e il valore della proprietà ValidationMessage
per qualsiasi regola di convalida che non riesce a convalidare i dati viene aggiunto alla raccolta Errors
dell'istanza di ValidatableObject<T>
. Infine, la proprietà IsValid
viene impostata e il relativo valore viene restituito al metodo chiamante, che indica se la convalida è riuscita o non è riuscita.
Attivazione della convalida quando le proprietà cambiano
La convalida viene attivata automaticamente anche ogni volta che viene modificata una proprietà associata. Ad esempio, quando un'associazione bidirezionale in LoginView
imposta la proprietà UserName
o Password
, viene attivata la convalida. Nell'esempio di codice seguente viene illustrato come si verifica questa situazione:
<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
<Entry.Behaviors>
<behaviors:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidateUserNameCommand}" />
</Entry.Behaviors>
</Entry>
Il controllo Entry
viene associato alla proprietà UserName.Value
dell'istanza di ValidatableObject<T>
e all'insieme Behaviors
del controllo è stata aggiunta un'istanza di EventToCommandBehavior
. Questo comportamento esegue il ValidateUserNameCommand
in risposta all'evento di TextChanged
generato sul Entry
, generato quando il testo in Entry
cambia. A sua volta, il delegato ValidateUserNameCommand
esegue il metodo ValidateUserName
, che esegue il metodo Validate
sull'istanza di ValidatableObject<T>
. Pertanto, ogni volta che l'utente immette un carattere nel controllo Entry
per il nome utente, viene eseguita la convalida dei dati immessi.
Visualizzazione degli errori di convalida
L'app multipiattaforma eShop notifica all'utente eventuali errori di convalida evidenziando il controllo che contiene i dati non validi con uno sfondo rosso e visualizzando un messaggio di errore che informa l'utente del motivo per cui i dati non sono validi sotto il controllo contenente i dati non validi. Quando i dati non validi vengono corretti, lo stato in background torna allo stato predefinito e il messaggio di errore viene rimosso. L'immagine seguente mostra LoginView
nell'app multipiattaforma eShop quando sono presenti errori di convalida.
Evidenziazione di un controllo che contiene dati non validi
.NET MAUI offre diversi modi per presentare informazioni di convalida agli utenti finali, ma uno dei modi più semplici consiste nell'usare Triggers
. Triggers
consente di modificare lo stato dei controlli, in genere per l'aspetto, in base a un evento o a una modifica dei dati che si verifica per un controllo. Per la convalida, verrà usato un DataTrigger
che ascolterà le modifiche generate da una proprietà associata e risponderà alle modifiche. I controlli Entry
nel LoginView
vengono configurati usando il codice seguente:
<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
<Entry.Style>
<OnPlatform x:TypeArguments="Style">
<On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
<On Platform="WinUI" Value="{StaticResource WinUIEntryStyle}" />
</OnPlatform>
</Entry.Style>
<Entry.Behaviors>
<mct:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidateCommand}" />
</Entry.Behaviors>
<Entry.Triggers>
<DataTrigger
TargetType="Entry"
Binding="{Binding UserName.IsValid}"
Value="False">
<Setter Property="BackgroundColor" Value="{StaticResource ErrorColor}" />
</DataTrigger>
</Entry.Triggers>
</Entry>
DataTrigger
specifica le proprietà seguenti:
Proprietà | Descrizione |
---|---|
TargetType |
Tipo di controllo a cui appartiene il trigger. |
Binding |
Markup dei dati Binding che fornirà notifiche di modifica e valore per la condizione del trigger. |
Value |
Valore dei dati da specificare quando la condizione del trigger è stata soddisfatta. |
Per questo Entry
, si ascolteranno le modifiche apportate alla proprietà LoginViewModel.UserName.IsValid
. Ogni volta che questa proprietà genera una modifica, il valore verrà confrontato con la proprietà Value
impostata nel DataTrigger
. Se i valori sono uguali, la condizione del trigger verrà soddisfatta e verranno eseguiti tutti gli oggetti Setter
forniti al DataTrigger
. Questo controllo dispone di un singolo oggetto Setter
che aggiorna la proprietà BackgroundColor
a un colore personalizzato definito usando il markup StaticResource
. Quando una condizione di Trigger
non viene più soddisfatta, il controllo ripristina le proprietà impostate dall'oggetto Setter
sullo stato precedente. Per ulteriori informazioni su Triggers
, consultare .NET MAUI Docs: Trigger.
Visualizzazione di messaggi di errore
L'interfaccia utente visualizza i messaggi di errore di convalida nei controlli Etichetta sotto ogni controllo i cui dati non sono stati convalidati. Nell'esempio di codice seguente viene illustrato il Label
che visualizza un messaggio di errore di convalida, se l'utente non ha immesso un nome utente valido:
<Label
Text="{Binding UserName.Errors, Converter={StaticResource FirstValidationErrorConverter}"
Style="{StaticResource ValidationErrorLabelStyle}" />
Ogni etichetta viene associata alla proprietà Errors
dell'oggetto modello di visualizzazione da convalidare. La proprietà Errors
viene fornita dalla classe ValidatableObject<T>
ed è di tipo IEnumerable<string>
. Poiché la proprietà Errors
può contenere più errori di convalida, l'istanza di FirstValidationErrorConverter
viene usata per recuperare il primo errore dalla raccolta per la visualizzazione.
Riepilogo
L'app multipiattaforma eShop esegue la convalida sincrona lato client delle proprietà del modello di visualizzazione e notifica all'utente di eventuali errori di convalida evidenziando il controllo contenente i dati non validi e visualizzando messaggi di errore che informano l'utente del motivo per cui i dati non sono validi.
Visualizzare le proprietà del modello che richiedono la convalida sono di tipo ValidatableObject<T>
e ogni istanza di ValidatableObject<T>
ha regole di convalida aggiunte alla relativa proprietà Validations
. La convalida viene richiamata dal modello di visualizzazione chiamando il metodo Validate
dell'istanza di ValidatableObject<T>
, che recupera le regole di convalida e le esegue sulla proprietà di valore ValidatableObject<T>
. Eventuali errori di convalida vengono inseriti nella proprietà Errors
dell'istanza di ValidatableObject<T>
e la proprietà IsValid dell'istanza di ValidatableObject<T>
viene aggiornata per indicare se la convalida è riuscita o non è riuscita.