sabato 22 settembre 2007

Windows Form e InputValidation

Ecco un piccolo esempio su come, generalmente, gestisco la validazione dei dati. Immaginiamo di avere un form che implementi una ipotetica scheda clienti con i seguenti campi: nome, cognome, indirizzo e numero telefonico. L'utente deve inserire necessariamente i primi tre campi e se inserisce anche il numero di telefono deve inserirlo ovviamente in un formato corretto. Se qualche campo viola le condizioni precedenti, il bottone per salvare i dati sul database viene disabilitato e accanto a quei campi che contengono dati non validi compare un messaggio di errore. Ingredienti: un form, 4 controlli TextBox accompagnati da altrettanti controlli Label, un controllo Button per il salvataggio dei dati, un ErrorProvider per i messaggi di errori e, infine, la piccolissima classe bcc_InputValidation che incontreremo tra qualche riga. Validare ogni controllo singolarmente è semplice, in questo esempio avendo solamente dei TextBox si sfrutta per questo scopo l'evento TextChanged. Sarebbe stato più corretto utilizzare l'evento Validating ma avremmo visto il risultato della validazione solo dopo essere usciti dal controllo, usando invece l'evento TextChanged avremo una validazione in tempo reale. La cosa più antipatica è invece il dover tenere traccia dello stato di tutti i controlli per decidere quando abilitare il bottone per il salvataggio. La classe bcc_InputValidation si occupa proprio di questo:


Private Class bcc_InputValidation

Private mht As New Hashtable

' serve ad indicare che la proprietà InputValido è cambiata
Public Event InputValidoChanged As EventHandler

' salva lo stato di ogni controllo che vogliamo monitorare
Public Sub SettaStato(ByVal str_NomeControllo As String,ByVal bool_Valido As Boolean)

If mht.ContainsKey(str_NomeControllo) Then

mht(str_NomeControllo) = bool_Valido

Else

mht.Add(str_NomeControllo, bool_Valido)

End If

' è cambiato il valore di InputValido
RaiseEvent InputValidoChanged(Me,New EventArgs)

End Sub

' Restituisce True se tutti i controlli sono validi
Public ReadOnly Property InputValido()
Get
Dim
val As Boolean

For Each val In mht.Values

' se trova un solo controllo non valido, restituisce False
If Not val Then Return False

Next


' Tutti i controlli sono validi
Return True

End Get

End Property

End Class


La proprietà Enabled del bottone ( btn_Salva ) che serve al salvataggio dei dati, viene messa in DataBinding con la proprietà InputValido dell'oggetto globale mInputValidation, istanza della classe bcc_InputValidation. Ovviamente, quando InputValido vale True il bottone verrà automaticamente abilitato, di contro, quando InputValido vale False il bottone verrà disabilitato. Vediamo un pò più nel dettaglio il funzionamento della classe bcc_InputValidation. Ogni volta che si esegue la validazione di un singolo controllo, si memorizza l'esito della validazione ( true o false ) nella HashTable della classe bcc_InputValidation attraverso il metodo SettaStato il quale poi si occuperà di lanciare un evento InputValidoChanged. E' proprio questo evento
che notifica al Databinding il cambiamento della proprietà pubblica InputValido determinando così lo stato ( abilitato o meno ) del bottone btn_Salva. Ecco il resto del codice:

Private Sub frmMain_Load(ByVal sender As Object,_
ByVal e As System.EventArgs) Handles Me.Load

' questa inizializzazione fa scattare l'input validation
txt_Cognome.Text = "..."
txt_Nome.Text = "..."
txt_Indirizzo.Text = "..."
txt_Telefono.Text = ""

' se tutti i controlli sono validi,
' il bottone salva viene abilitato

btn_Salva.DataBindings.Add("Enabled", mInputValidation, "InputValido")

End Sub

Private Sub
btn_Salva_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles btn_Salva.Click

' ....
' qui vanno le chiamate al database
' ...


MsgBox("dati salvati correttamente")

End Sub

Private Sub
txt_TextChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txt_Nome.TextChanged

Dim txt As TextBox = sender

' per default setta lo stato del controllo a valido
mInputValidation.SettaStato(txt.Name, True)
ep_ErrorProvider.SetError(txt, "")

If txt.Text.Trim = "" Then

mInputValidation.SettaStato(txt.Name, False)
ep_ErrorProvider.SetError(txt, "campo richiesto!")

End If

End Sub

Private Sub
txt_Telefono_TextChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txt_Telefono.TextChanged

mInputValidation.SettaStato("txt_Telefono", True)
ep_ErrorProvider.SetError(txt_Telefono, "")

' non è un campo richiesto
If txt_Telefono.Text.Trim = "" Then Exit Sub

' se l'utente ha inserito il telefono, validiamolo
If Not Regex.IsMatch(txt_Telefono.Text.Trim, "^[+]?[0-9 ]+$") Then

mInputValidation.SettaStato("txt_Telefono", False)
ep_ErrorProvider.SetError(txt_Telefono, "formato non valido!")

End If

End Sub




A questo link il progetto completo.

Nessun commento: