Μέρος 3

Validation
----------------

Πολλές φορές ακούμε τον όρο Validation στην ορολογία της δημιουργίας ενός λογισμικού και μας έρχονται στο μυαλό λέξεις όπως «λάθος», «χρήστης», «μήνυμα λάθους», «MessageBox» κλπ. Εν μέρη, έχουμε δίκιο. Κατά την διάρκεια του Validation προσπαθούμε να δούμε έαν η τιμή η οποία έχουμε πάρει απο τον χρήστη είναι σωστή, εάν κάποιο checkbox είναι ενεργοποιημένο ώστε να εκτελέσουμε κάποια λειτουργία πρωτού προβούμε στην τελική λειτουργία (καταχώρηση, διαγραφή κλπ) κλπ. Για να μπορέσω να γίνω περισσότερο κατανοητός, ας θεωρήσουμε ότι έχουμε μια καρτέλα πελάτη μπροστά μας σε μια καλοσχεδιασμένη, αισθητικά και λειτουργικά, φόρμα. Επίσης πρωτού συνεχίσουμε παρακάτω θέλω να αναφέρω ορισμένες λεπτομέριες που υπάρχουν στα controls που χρησιμοποιώ εγώ. Σε κάθε (σχεδόν) Form Control μου, υπάρχει ενα Property το οποίο το ονομάζω ErrorState που απο default η τιμή του είναι None. Αυτό το έχω καταφέρει κάνοντας extend το Control σε κάποιο class και προσθέτοντας το Property εκεί. Το property έχει τιμές απο enum με fields όπως None, Critical, Medium, Less, WrongValue κλπ. Όπως καταλαβαίνετε ανάλογα με το πόσο σημαντικό είναι το control κατα το validation, ανάλογο είναι και το state του μετά το validation ώστε να ξέρω πως ακριβώς θα το παρουσιάσω στο χρήστη και σε πιο σημείο μέσα στο ErrorBox μου.

Κατά την διάρκεια μιας καταχώρησης ενός πελάτη, η φόρμα μας προαπαιτεί κάποια στοιχεία να είναι συμπληρωμένα, όπως για παράδειγμα το όνομα, το επίθετο, το ΑΦΜ και κάποιο μοναδικό κωδικό αναγνώρισης του πελάτη. Εάν ο χρήστης δεν συμπληρώσει κανένα απολύτως στοιχείο, τότε εμφανίζουμε ένα μήνυμα λάθους στο StatusBar και θέτουμε το ErrorState του Control μας σε Critical για κάθε Mandatory (απαραίτητο) στοιχείο (field) το οποίο έχουμε. Επόμενο βήμα είναι να θέσουμε το χρώμα (border του control) στο Color, το οποίο έχουμε ορίσει στο Color Code της εφαρμογής μας ως ErrorState Color, πχ κόκκινο (IndianRed) ώστε ο χρήστης να μπορεί με μια ματιά να βρεί πιο ακριβώς είναι το λάθος του και σε πιο σημείο της φόρμας.

Εάν ο χρήστης έχει συμπληρώσει το πεδίο, αλλά με μια μή αποδεκτή τιμή τότε θέτουμε το ErrorState Color στο border και την τιμή του ErrorState σε WrongValue. Έτσι όταν τελειώσει το Validation εμφανίζουμε ένα συνοπτικό και περιεκτικό μήνυμα λάθους, περιγράφοντας το λάθος, τις επιτρεπτές τιμές και εφόσον είναι εφικτό, προτείνουμε και κάποιες τιμές για το πεδίο ή δίνουμε κάποιο παράδειγμα ή προτείνουμε στον χρήστης να αφήσει το πρόγραμμά μας να θέσει την Default τιμή στο πεδίο. Έτσι ακόμα κι αν τα λάθη είναι παραπάνω απο ένα, τα εμφανίζουμε όλα το ένα κάτω απο το άλλο σε κάπoιο custom Form το οποίο έχουμε φτιάξει γι αυτό το σκοπό και το οποίο υποστηρίζει εύκολα όλα τα παραπάνω παραδείγματα (παραδείγματα, default τιμές κλπ).

Πώς μπορούμε όμως να περιορίσουμε τα λάθη κατα την εισαγωγή των στοιχείων, ώστε να έχουμε λιγότερο overhead απο το Validation, πριν απο κάποια λειτουργία;

Είναι πολύ εύκολο. Έχουν παρουσιαστεί κάποια νέα controls, όπως το MaskedTextBox . Χρησιμοποιώντας το, μπορούμε να γλυτώσουμε πολύ χρόνο και λάθη κατα την εισαγωγή των στοιχείων απο τον χρήστη. Τοποθετώντας έναν «οδηγό» στα πεδία τα οποία μπορούμε να προβλέψουμε τις τιμές τους (πχ κινητό τηλέφωνο) βοηθάμε τον χρήστη να μην κάνει λάθη, να τελειώσει γρηγορότερα την καταχώρηση και φυσικά να μην χάσει χρόνο προσπαθώντας να μαντέψει τι ακριβώς πρέπει να συμπληρώσει σε εκείνο το πεδίο ή με ποιο τρόπο πρέπει να το γράψει.Πχ όπως ανέφερα πριν, εάν θέλουμε ο χρήστης να συμπληρώσει το κινητό τηλέφωνο τότε γράφουμε απλά στο Property «Mask» την τιμή «0000000000». Αυτό θα εμφανίσει όταν τρέξουμε την φόρμα μας σαν οδηγό το _________ και δέχετε μόνο ψηφία σαν τιμή για κάθε «0» το οποίο περάσαμε στο Mask. Επίσης μπορούμε να αποφύγουμε λάθη χρησιμοποιώντας απλά ή πολύπλοκα Regular Expressions ανάλογα με την περίσταση.

Έχω Vista. Ποια πλεονεκτήματα έχω ;

Η αλήθεια είναι οτι δεν χρειάζεται καν πλέον να φτιάξουμε ένα δικό μας ErrorBox για να κάνουμε όλα τα παραπάνω. Η Microsoft και τα Windows Vista παρουσιάζουν μερικά νέα χαρακτηριστικά τα οποία μας λύνουν τα χέρια σε τέτοια θέματα. Μερικά είναι ο νέος TaskDialog και το TaskDialogIndirect API όπως και τα CommandLinks του. Χρησιμοποιώντας τον TaskDialog μπορώ να παρουσιάσω πολύ αναλυτικά και προσεκτικά σχεδιασμένα ErrorBoxes τα οποία είναι λειτουργικά (κάνουν όλα τα παραπάνω με ελάχιστο κώδικα), είναι native (έχουν το ίδιο αποτέλεσμα σε όλα τα pc) και προσφέρουν κάποια χαρακτηριστικά τα οποία θα θέλαμε πολύ να υπάρχουν στο δικό μας Form (ErrorBox), όπως για παράδειγμα More options feature για Advanced λειτουργίες, τις οποίες τις «κρύβουμε» απο τον Novice χρήστη. Μπορούμε δηλαδή να εμφανίσουμε αναλυτικότερη περιγραφή του προβλήματος σε έναν προχωρημένο χρήστη, απο ένα απλό μήνυμα λάθους για τον αρχάριο χρήστη ή ακόμα και να προσφέρουμε προκαθορισμένες ή εναλλακτικές ενέργειες σε CommandLinks είτε για τον αρχάριο, είτε για τον προχωρημένο χρήστη.

Ακολουθούν 2 εικόνες οι οποίες δείχνουν τα παραπάνω:

TaskDialog:

CommandLinks:


* Οι εικόνες είναι απο το site της Microsoft

A Custom Validator

Μια καλή ιδέα και προσέγγιση είναι να φτιάξουμε έναν custom Validator ώστε να μην χρειάζεται κάθε φορά που θέλουμε να εκτελέσουμε συγκεκριμένες λειτουργίες Validation να γράφουμε τον ίδιο και τον ίδιο κώδικα μέσα στα event των Controls μας.
Μια Class με Static Methods για Validation είναι ότι πρέπει για κάθε περίπτωση. Κάθε Static Method θα επιστρέφει (λογικά) κάποιο Boolean το οποίο θα είναι true εάν το Validation ήτανε επιτυχημένο ή όχι. Μάλιστα εάν περνάμε και το Control μας σαν Reference parameter (ώστε να θέτει ο ίδιος ο Validator το ErrorState) τότε γλυτώνουμε και χρόνο και κώδικα και ενδεχομένος και λάθη.


Hints, Tips and Snips

  • Μην αλλάζετε το Background Color στο στοιχείο που έχετε λάθος/θέλετε να τονίσετε. Αλλάξτε το Border Color.
  • Μην αφήνετε τον χρήστη να γράψει πρώτα λάθος τιμή και μετά να του το πείτε οτι έγραψε λάθος.
  • Διορθώστε τα λάθη του μόνοι σας εάν μπορείτε να τα «βρείτε»/προβλέψετε.Πχ Θέλετε μόνο κεφαλαία σε κάποιο πεδίο; Γράψτε κώδικα ο οποίος μετατρέπει οτιδήποτε γράφει ο χρήστης σε κεφαλαίο in real time. *Snip1
  • Αποφεύγετε να χρησιμοποιείτε κώδικα ο οποίος δεν είναι δοκιμασμένος σε διάφορα scenarios και δεν είναι αρκετά έξυπνος. Πχ  Θέλετε να δέχετε μόνο διψήφιους αριθμούς σαν input, το textBox1.TextLength == 2 δεν είναι αρκετό για να διασφαλίσει οτι θα πάρετε 2 ψηφία, καθώς μπορεί να είναι και γράμματα. *Snip2
  • Χρησιμοποιήστε όπου μπορείτε maskedTextBoxes (πχ στην περίπτωση απο πάνω)
  • Χρησιμοποιήστε όπου μπορείτε DropDownBoxes με προκαθορισμένες τιμές



Snip1:
Μετατρέπει ότι χαρακτήρα γράφετε στο TextBox σε κεφαλαίο.

 

textBox1.KeyPress += new KeyPressEventHandler(textBox1_KeyDown);
  

void textBox1_KeyDown(object sender, KeyPressEventArgs e)

{

           

      textBox1.Text += (e.KeyChar.ToString().ToUpper());

      //A small trick to place cursor to the end of box

      textBox1.SelectionStart = textBox1.TextLength;

//We handled the event

      e.Handled = true;

}


-------

Snip2:

maskedTextBox1.Mask = "00";

-------

Snip3:
Χρησιμοποιήστε το παρακάτω όταν θέλετε να διαπιστώστε εάν ένα textbox έχει τιμή διαφορετική του 
"" (κενό) ή  οχι.

Το
textBox1.TextLength != 0
είναι πιο γρήγορο και παράγει λιγότερο IL κώδικα απο το
textBox1.Text != ""

-----------------------
Εδώ τελείωσε και το κομμάτι του Validation. Δεν έχω τελειώσει τα files τα οποία υποσχέθηκα μαζί με το post, θα τα τελειώσω όμως εντός της εβδομάδας. Επίσης ετοιμάζω κάποια screencasts και posts για XAML/Vista και τον καταπληκτικό Microsoft Interactive Designer. Θεωρώ πολύ ωραίο κομμάτι τον τρόπο με τον οποίο δένουμε το InfoCard Space (.Νet 3.0) με GUI και πως αυτό μπορεί να μας δώσει ενα πολυχρηστικό περιβάλλον χωρίς πολύπλοκους μηχανισμούς security κλπ.