Convalida nelle app aziendali
Nota
Questo eBook è stato pubblicato nella primavera del 2017 e non è stato aggiornato da allora. C'è molto nel libro che rimane prezioso, ma alcuni dei materiali sono obsoleti.
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 applica regole business e impedisce 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 per dispositivi mobili eShopOnContainers 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. La figura 6-1 mostra le classi coinvolte nell'esecuzione della convalida nell'app per dispositivi mobili eShopOnContainers.
Figura 6-1: Classi di convalida nell'app per dispositivi mobili eShopOnContainers
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 Validate
metodo dell'istanza ValidatableObject<T>
, che recupera le regole di convalida e le esegue sulla ValidatableObject<T>
Value
proprietà . Eventuali errori di convalida vengono inseriti nella Errors
proprietà dell'istanza ValidatableObject<T>
e la IsValid
proprietà dell'istanza viene aggiornata per indicare se la ValidatableObject<T>
convalida ha avuto esito positivo o negativo.
La notifica di modifica delle proprietà viene fornita dalla classe ExtendedBindableObject
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 boolean
Check
metodo utilizzato per eseguire la convalida richiesta e una ValidationMessage
proprietà il cui valore è il messaggio di errore di convalida che verrà visualizzato se la convalida non riesce.
L'esempio di codice seguente illustra 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 per dispositivi mobili eShopOnContainers:
public class IsNotNullOrEmptyRule<T> : IValidationRule<T>
{
public string ValidationMessage { get; set; }
public bool Check(T value)
{
if (value == null)
{
return false;
}
var str = value as string;
return !string.IsNullOrWhiteSpace(str);
}
}
Il Check
metodo restituisce un boolean
valore che indica se l'argomento value è null
, vuoto o è costituito solo da spazi vuoti.
Anche se non usato dall'app per dispositivi mobili eShopOnContainers, l'esempio di codice seguente mostra una regola di convalida per la convalida degli indirizzi di posta elettronica:
public class EmailRule<T> : IValidationRule<T>
{
public string ValidationMessage { get; set; }
public bool Check(T value)
{
if (value == null)
{
return false;
}
var str = value as string;
Regex regex = new Regex(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$");
Match match = regex.Match(str);
return match.Success;
}
}
Il Check
metodo restituisce un boolean
valore 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 valore della Match
proprietà dell'oggetto Success
.
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 per dispositivi mobili eShopOnContainers visualizzare le proprietà del modello che richiedono la convalida sono 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
{
return _userName;
}
set
{
_userName = value;
RaisePropertyChanged(() => UserName);
}
}
public ValidatableObject<string> Password
{
get
{
return _password;
}
set
{
_password = value;
RaisePropertyChanged(() => Password);
}
}
Affinché si verifichi la convalida, è necessario aggiungere regole di convalida alla Validations
raccolta di ogni ValidatableObject<T>
istanza, 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 per dispositivi mobili eShopOnContainers può attivare manualmente la convalida di una proprietà e attivare automaticamente la convalida quando una proprietà cambia.
Attivazione manuale della convalida
La convalida può essere attivata manualmente per una proprietà del modello di visualizzazione. Ad esempio, questo si verifica nell'app per dispositivi mobili eShopOnContainers quando l'utente tocca il pulsante Login in 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 Validate
metodo esegue la convalida del nome utente e della password immessi dall'utente in LoginView
, richiamando il metodo Validate in ogni ValidatableObject<T>
istanza. Nell'esempio di codice seguente viene illustrato il metodo Validate dalla ValidatableObject<T>
classe :
public bool Validate()
{
Errors.Clear();
IEnumerable<string> errors = _validations
.Where(v => !v.Check(Value))
.Select(v => v.ValidationMessage);
Errors = errors.ToList();
IsValid = !Errors.Any();
return this.IsValid;
}
Questo metodo cancella l'insieme Errors
e quindi 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 cambiano le proprietà
La convalida può essere attivata 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 in ValidateUserNameCommand
risposta all'evento [TextChanged
] generato su Entry
, generato quando il testo nelle Entry
modifiche viene generato. 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.
Per altre informazioni sui comportamenti, vedere Implementazione di comportamenti.
Visualizzazione degli errori di convalida
L'app per dispositivi mobili eShopOnContainers notifica all'utente eventuali errori di convalida evidenziando il controllo che contiene i dati non validi con una riga rossa 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, la riga diventa nera e il messaggio di errore viene rimosso. La figura 6-2 mostra LoginView nell'app per dispositivi mobili eShopOnContainers quando sono presenti errori di convalida.
Figura 6-2: Visualizzazione di errori di convalida durante l'accesso
Evidenziazione di un controllo contenente dati non validi
Il LineColorBehavior
comportamento associato viene usato per evidenziare Entry
i controlli in cui si sono verificati errori di convalida. Nell'esempio di codice seguente viene illustrato come il LineColorBehavior
comportamento associato è associato a un Entry
controllo :
<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
<Entry.Style>
<OnPlatform x:TypeArguments="Style">
<On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
<On Platform="UWP" Value="{StaticResource UwpEntryStyle}" />
</OnPlatform>
</Entry.Style>
...
</Entry>
Il Entry
controllo utilizza uno stile esplicito, illustrato nell'esempio di codice seguente:
<Style x:Key="EntryStyle"
TargetType="{x:Type Entry}">
...
<Setter Property="behaviors:LineColorBehavior.ApplyLineColor"
Value="True" />
<Setter Property="behaviors:LineColorBehavior.LineColor"
Value="{StaticResource BlackColor}" />
...
</Style>
Questo stile imposta le ApplyLineColor
proprietà associate e LineColor
del LineColorBehavior
comportamento associato nel Entry
controllo . Per altre informazioni sugli stili, vedere Stili.
Quando il valore della ApplyLineColor
proprietà associata viene impostato o modificato, il LineColorBehavior
comportamento associato esegue il OnApplyLineColorChanged
metodo , illustrato nell'esempio di codice seguente:
public static class LineColorBehavior
{
...
private static void OnApplyLineColorChanged(
BindableObject bindable, object oldValue, object newValue)
{
var view = bindable as View;
if (view == null)
{
return;
}
bool hasLine = (bool)newValue;
if (hasLine)
{
view.Effects.Add(new EntryLineColorEffect());
}
else
{
var entryLineColorEffectToRemove =
view.Effects.FirstOrDefault(e => e is EntryLineColorEffect);
if (entryLineColorEffectToRemove != null)
{
view.Effects.Remove(entryLineColorEffectToRemove);
}
}
}
}
I parametri per questo metodo forniscono l'istanza del controllo a cui è associato il comportamento e i valori precedenti e nuovi della ApplyLineColor
proprietà associata. La EntryLineColorEffect
classe viene aggiunta all'insieme del Effects
controllo se la ApplyLineColor
proprietà associata è true
, in caso contrario viene rimossa dalla raccolta del Effects
controllo. Per altre informazioni sui comportamenti, vedere Implementazione di comportamenti.
La EntryLineColorEffect
sottoclasse della RoutingEffect
classe e viene illustrata nell'esempio di codice seguente:
public class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("eShopOnContainers.EntryLineColorEffect")
{
}
}
La RoutingEffect
classe rappresenta un effetto indipendente dalla piattaforma che esegue il wrapping di un effetto interno specifico della piattaforma. Ciò semplifica il processo di rimozione dell'effetto, poiché non è previsto l'accesso alle informazioni sul tipo in fase di compilazione per un effetto specifico della piattaforma. Chiama EntryLineColorEffect
il costruttore della classe base, passando un parametro costituito da una concatenazione del nome del gruppo di risoluzione e dall'ID univoco specificato in ogni classe di effetti specifica della piattaforma.
L'esempio di codice seguente illustra l'implementazione eShopOnContainers.EntryLineColorEffect
per iOS:
[assembly: ResolutionGroupName("eShopOnContainers")]
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]
namespace eShopOnContainers.iOS.Effects
{
public class EntryLineColorEffect : PlatformEffect
{
UITextField control;
protected override void OnAttached()
{
try
{
control = Control as UITextField;
UpdateLineColor();
}
catch (Exception ex)
{
Console.WriteLine("Can't set property on attached control. Error: ", ex.Message);
}
}
protected override void OnDetached()
{
control = null;
}
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(args);
if (args.PropertyName == LineColorBehavior.LineColorProperty.PropertyName ||
args.PropertyName == "Height")
{
Initialize();
UpdateLineColor();
}
}
private void Initialize()
{
var entry = Element as Entry;
if (entry != null)
{
Control.Bounds = new CGRect(0, 0, entry.Width, entry.Height);
}
}
private void UpdateLineColor()
{
BorderLineLayer lineLayer = control.Layer.Sublayers.OfType<BorderLineLayer>()
.FirstOrDefault();
if (lineLayer == null)
{
lineLayer = new BorderLineLayer();
lineLayer.MasksToBounds = true;
lineLayer.BorderWidth = 1.0f;
control.Layer.AddSublayer(lineLayer);
control.BorderStyle = UITextBorderStyle.None;
}
lineLayer.Frame = new CGRect(0f, Control.Frame.Height-1f, Control.Bounds.Width, 1f);
lineLayer.BorderColor = LineColorBehavior.GetLineColor(Element).ToCGColor();
control.TintColor = control.TextColor;
}
private class BorderLineLayer : CALayer
{
}
}
}
Il OnAttached
metodo recupera il controllo nativo per il Xamarin.FormsEntry
controllo e aggiorna il colore della linea chiamando il UpdateLineColor
metodo . L'override OnElementPropertyChanged
risponde alle modifiche alle proprietà associabili nel Entry
controllo aggiornando il colore della linea se la proprietà associata LineColor
cambia o la Height
proprietà delle Entry
modifiche. Per altre informazioni sugli effetti, vedere Effetti.
Quando nel controllo vengono immessi Entry
dati validi, verrà applicata una linea nera alla fine del controllo per indicare che non è presente alcun errore di convalida. La figura 6-3 mostra un esempio di questo.
Figura 6-3: Riga nera che indica nessun errore di convalida
Il Entry
controllo dispone inoltre di un oggetto DataTrigger
aggiunto alla relativa Triggers
raccolta. L'esempio di codice seguente illustra :DataTrigger
<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
...
<Entry.Triggers>
<DataTrigger
TargetType="Entry"
Binding="{Binding UserName.IsValid}"
Value="False">
<Setter Property="behaviors:LineColorBehavior.LineColor"
Value="{StaticResource ErrorColor}" />
</DataTrigger>
</Entry.Triggers>
</Entry>
Questo DataTrigger
monitora la UserName.IsValid
proprietà e, se il valore diventa false
, esegue , Setter
che modifica la LineColor
proprietà associata del LineColorBehavior
comportamento associato in rosso. La figura 6-4 mostra un esempio di questo.
Figura 6-4: Linea rossa che indica l'errore di convalida
La riga nel Entry
controllo rimarrà rossa mentre i dati immessi non sono validi, altrimenti cambierà in nero per indicare che i dati immessi sono validi.
Per altre informazioni sui trigger, vedere Trigger.
Visualizzazione dei 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. L'esempio di codice seguente mostra che Label
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 Label
oggetto viene associato alla Errors
proprietà dell'oggetto modello di visualizzazione da convalidare. La proprietà Errors
viene fornita dalla classe ValidatableObject<T>
ed è di tipo List<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 per dispositivi mobili eShopOnContainers 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 Validate
metodo dell'istanza ValidatableObject<T>
, che recupera le regole di convalida e le esegue sulla ValidatableObject<T>
Value
proprietà . Eventuali errori di convalida vengono inseriti nella Errors
proprietà dell'istanza ValidatableObject<T>
e la IsValid
proprietà dell'istanza viene aggiornata per indicare se la ValidatableObject<T>
convalida ha avuto esito positivo o negativo.