Preventing Users from Leaving Invalid Controls
In a Validating
event handler, you can prevent users from leaving the control containing the invalid entry until they clear or fix the error. If you look back to the code that assigned the event handler to the control, you will note that it wrapped the method in a CancelEventHandler. That provides the flexibility to add this line in the textBox1_Validating method, just after the error message is set (in the catch block):
e.Cancel = true;
That line of code suppresses any events that would normally follow the Validating
event. To users, the code causes the cursor to remain stubbornly in the control; neither tabbing nor mousing will get it to budge until the user corrects the error. For more information on the Validating
event, see this MSDN article
Here's how an ErrorProvider actually renders on screen. Consider the simple form shown in Figure 1
. I will refer to this form throughout the remainder of this article.
|Figure 1. Simple Form: This simple formused as an example in this articlecontains an unbound DataGridView, two TextBox controls, and OK and Cancel buttons.|
|Figure 2. ErrorProvider UI: The ErrorProvider displays an icon when a validation error occurs. By hovering over the icon, users can read the error message associated with that error.||
By attaching the Validating
method discussed earlier to the left text box, and entering characters that do not represent a number, the ErrorProvider pops up a small error icon. When the user hovers the mouse over the error icon, a ToolTip opens to show the error message provided: in this case, the text "Not an integer value." (see Figure 2
So as you have seen, the ErrorProvider simplifies building user interfaces for form validation. But so far, everything you've seen involves laboriously hand-coding an xxx_Validating
method for each and every Control on your form. As Larry Wall said in Programming Perl
, one of the three great programming virtues is laziness.
"The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labour-saving programs that other people will find useful, and document what you wrote so you don't have to answer so many questions about it."
Which means in this case that there should be a better way. And there is. Enter the CleanCode.Forms.Validator class.
A Better Solution
Imagine a validation engine that wraps around an ErrorProvider but more flexibleso it allows Label controls to show error messages (for those who do not care for hovering with the mouse). To avoid limiting developers, the engine should allow custom validation to co-exist with the automatic validation features, if not be integrated.
With that in mind, consider the nature of validation and the notion of business rules. For example, suppose you have a form field for entering a US phone number. Implicit in that requirement is a slew of assumptions about what constitutes a phone number. These business rules might include:
- Only digits and hyphens are allowed.
- When hyphens are present, the entry must contain exactly 12 characters (10 digits and 2 hyphens).
- The hyphens must be after the third and the seventh digits.
- If hyphens are omitted, the entry must be precisely 10 characters.
Typically, people think of business rules as something specific to their
business rather than any
business, but the rules listed above are still business rules in a broad sense in that they refer to the semantics of the data. Here's one more business rule that is
specific to the example business rather than a universal character of US phone numbers:
- Area codes must be for California only.
Many software applications that process form input simply hard-code the business rule checking right in with the form processing, using logic something like this:
if (phoneNumber contains only digits and hyphens) and
getAreaCode(phoneNumber) is on the California list of area codes
flag invalid phone number
But then what if the company wants to expand to Oregon and Washington also? That would require changing the code because of a business rule change. This is worse than wearing white shoes after Labor Dayit simply should not be done in polite societyor, in this case, in clean code. Many software developers will let the data
be external to the program but far fewer will let the rules
be external to the program. And that is where a well-designed validation engine shines, by allowing the business rules to be external to the program and therefore controllable by a business analyst rather than a software designer.
The scope of the validation engine in this article, then, will be:
- Encapsulate business rules externally.
- Manifest validation errors with either a form-global ErrorProvider or a control-specific Label.
- Allow custom validation beyond the scope of the validation engine to co-exist.