Validazione dei dati in Silverlight 4.0

di Francesco Abbruzzese, in Silverlight,

Anche se Silverlight nasce come sottoinsieme di .NET, in Silverlight 4.0 stata introdotta una tecnica avanzata di validazione dei dati basata sull'interfaccia INotifyDataErrorInfo non ancora disponibile in WPF. L'utilizzo di strumenti specifici per validare l'input dell'utente, ovvero per verificare se è conforme alle regole di business, semplifica notevolmente lo sviluppo di applicazioni in quanto permette di separare la logica di gestione degli errori di validazione dal normale flusso del controllo. Ciò comporta una serie di vantaggi i principali dei quali sono:

  1. Si evita di complicare il flusso del controllo con la miriade di condizioni necessarie ad isolare e propagare gli errori sino al luogo in cui dovranno essere mostrati;
  2. Si concentra la definizione delle regole di validazione in un'unica zona di codice;
  3. La logica generale di gestione delle regole e degli errori si implementa una volta per tutte all'interno degli strumenti per la validazione degli errori.

INotifyDataErrorInfo deve essere implementata dalla classe di business che viene messa in "binding" con l'interfaccia grafica. Ciò significa che le regole di validazione vengono definite nelle classi di business e non nell'interfaccia. Questo è un grande passo avanti rispetto ai Validator di ASP.NET o alle ValidationRule di WPF perchè anche se l'input dell'utente ed i messaggi di errore vengono inseriti nell'interfaccia, le regole di validazione appartengo al livello di business e non ha senso ridefinirle ogni volta che si desidera cambiare l'interfaccia grafica.

INotifyDataErrorInfo ha anche dei vantaggi sul suo predecessore IDataErrorInfo in quanto, a differenza di esso, permette di associare più di un messaggio di errore ad ogni propietà dell'oggetto di business e, principalmente, permette di trasmettere in modo asincrono errori all'interfaccia attraverso un evento. Ciò ci permette di riflettere immediatamente nell'interfaccia errori generati in seguito alla trasmissioni asincrone dei dati inseriti ad un Web Service.

Lo strumento più adatto a definire le regole di validazione in ambitio .NET e Silvelight sono le Data Annotations che permettono di associare regole di validazione ad una proprietà o ad un intera classe semplicemente decorando le stesse con degli attributi. In questo modo il codice che definisce le regole di validazione viene separato dal codice per gestire il normale flusso del controllo, aumentando notevolmente la manutenibilità e leggibilità del codice. Inoltre, essendo le regole di validazione separate dalle classi che le utilizzano, possono essere facilmente riutilizzate in più classi.

C'è da chiedersi allora, perchè nella versione 4.0 di Silverlight sia stato scelto di fornire supporto a INotifyDataErrorInfo invece che alle Data Annotations. La risposta non è difficile da immaginare: Silverlight nasce sostanzialmente come framework client e questo significa che le classi di business, e quindi anche le regole di validazione, sono definite sul server in .NET.
Probabilmente INotifyDataErrorInfo è lo strumento ideale per funzionare in qualche modo da "proxy", per applicare sul client le regole di validazione definite sul server sia usando le Data Annotations ma qualsiasi altro meccanismo che verrà elaborato in futuro.

In effetti, questo è ciò che accade neiWCF RIA Services, dove le regole sono definite con Data Annotations sul server e vengono riflesse lato client con l'aiuto di un'implementazione di INotifyDataErrorInfo.

Sfortunatamente, come discuteremo meglio in seguito, in molti casi non possiamo avvalerci dell'aiuto dei WCF RIA Services e siamo quindi costretti a riflettere manualmente, in qualche modo, le regole di validazione definite sul server utilizzando INotifyDataErrorInfo.

Nell'articolo, dopo aver analizzato INotifyDataErrorInfo e le Data Annotations, discuteremo il tipo di aiuto che può venirci dai WCF RIA Services, ed infine presenteremo il Validation Toolkit for WPF & Silverlight: una libreria che può aiutarci a fornire in Silverlight un supporto alle Data Annotations in modo indipendente dall'utilizzo dei WCF RIA Services, ma anche a trasmettere errori di validazione generati dal server al client Silverlight, cosa che, come vedremo in seguito, presenta qualche problema dovuto alla natura di plug-in per browser.

Validazione con l'Interfaccia INotifyDataErrorInfo

L'interfaccia INotifyDataErrorInfo è definita come:

public interface INotifyDatAErrorInfo
{
  bool HasErrors { get; }
  IEnumerable GetErrors(string propertyName);
  event EventHandler<DataErrrorsChangedEventArgs> ErrorsChange;
}

L'evento ErrorsChange deve essere fatto scattare quando vi è un cambiamento nello stato di errore. HasErrors indica se l'oggetto è in uno stato di errore. Infine GetErrors ritorna la lista di errori associata a propertyName. Se propertyName è una stringa nulla devono essere ritornati gli errori non associabili ad alcuna propietà specifica, ovvero quelli derivanti da vincoli di validazione che coinvolgono più proprietà.

Vediamo con un semplice esempio la tecnica base di implementazione dell'interfaccia INotifyDataErrorInfo.

Supponiamo di avere una classe Interval con due sole propietà di tipo intero:Low e High che devono essere entrambe comprese tra 0 e 100 eLow deve essere sempre minore o ugulale ad High. Una possibile implementazione di GetErrors è la seguente:

public System.Collections.IEnumerable GetErrors(string x)
{
  if ((x == "Low" && (Low < 0 || Low > 100)) ||
      (x == "High" && (High < 0 || High > 100)))
    return "Gli estremi dell'intervallo devono essere compresi tra 0 e 100";
  else if (x == string.Empty && High < Low)
    return "L'estremo inferiore deve essere minore dell'estremo superiore";
  else
    return string.Empty;
}

Invece, una possibile implementazione di HasErrors è:

public bool HasErrors
{
  get
  {
    return Low > High || Low < 0 || High < 0 || Low > 100 || High > 100;
  }
}

Infine nel setter delle due propietà ogni volta che ci arriva un nuovo valore dobbiamo invocare una funzione RaiseErrorsChanged(propertyName) definita così:

public void RaiseErrorsChanged(string propertyName)
{
  if (ErrorsChanged != null)
    ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
3 pagine in totale: 1 2 3
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti