nput validation is something that every program needs, and every programmer dreads. Most developers craft hard-coded program logic to verify that a phone number consists of 7 or 10 digits; that an IP address consists of 4 octets; that a country name matches 1 of 193 choices, etc. While .NET 2.0 provides some support for streamlining input validation, it barely scratches the surface of automating and simplifying the input validation process. If you ever search MSDN for the topic, you'll find most of the articles discuss hard-coded validationbut maintaining hand-written, custom code for each element that requires validation is a maintenance nightmare.
Furthermore, it's unnatural to conceptualize the steps of validation as programming steps
(i.e. if this then that...); it's far more intuitive to consider the qualities
of the data to be validated. For example, if you were describing the input, you might say, "It should be between five and eight characters; it should be numeric and non-negative; it should always end in the digit '5,' etc."
The concept of considering the data qualities rather than the validation process leads to the validation engine discussed in this article. A modular, data-driven validation engine approach provides a more natural interface, more flexibility, and is easier to maintain. Visual Studio lets you specify property values at design time for a variety of components; using that approach for defining validation attributes is a natural extension, and makes incorporating robust validation simpler for developers. The flexibility of storing validation settings in a configuration file makes validation easy to change, allowing developers and administrators to modifiy or customize validation properties without recompiling and redeployingand without needing the source code. You'll find that using the validation engine discussed here, you can instrument a wide range of validation criteria with very few lines of code.
You want your program to validate form input, provide feedback to the user, and perhaps take other actions to handle the condition. And you want to do this simply and easily.
This article presents a useful solution, though not a complete
solution for every case. Instead, it follows the 80/20 rule: The validation engine will be useful in about 80 percent of the use cases you might need to address. Also following the 80/20 rule, to cover the remaining use cases would require 80 percent of the effort (i.e. the effort expended to get this far would be multiplied five-fold).
So, for example, you'll find that the engine doesn't handle validation interaction between multiple fields; instead, I opted to focus on single-field validation for this introductory article.
Initial Solution: The ErrorProvider Component
To begin, you need to be aware of the handy Microsoft component called ErrorProvider (see the MSDN article "ErrorProvider Component Overview
"). Dragging an ErrorProvider onto the visual designer (or instantiating it in code) gives you the basic component required to display validation messages. For example, here's a typical example that uses an ErrorProvider (from the MSDN article "How to: Display Error Icons for Form Validation with the Windows Forms ErrorProvider Component
protected void textBox1_Validating(object sender, CancelEventArgs e)
int x = Int32.Parse(textBox1.Text);
catch (Exception e)
errorProvider1.SetError(textBox1, "Not an integer value.");
This code validates input into a TextBox, requiring that it be an integer. To test the entered value, the code uses the Int32.Parse
method, which throws an exception when the TextBox's string value can not be converted to an integer. When the input passes this validation test, the ErrorProvider.SetError
invocation clears the existing error message, if any; otherwise the catch
block calls the ErrorProvider.SetError
method to display the "Not an integer value" message.
You'd attach this method to the Validating
event of a particular TextBox control called textBox1, either with the visual designer or programmatically with this code:
You should be aware of several important facts that are not terribly clear from the documentation.
event occurs when a control yields focus to another control. So the event occurs when you use the tab key to move away from the current control or when you click another control with the mouse.
Note that the SetError
method in the example takes a Control as its first argument. That allows the single ErrorProvider to simultaneously handle error messages for a multiplicity of controls.
The second argument to SetError is the message to display. Passing an empty string tells the ErrorProvider to suppress the error message indicator completely, so it's important not only to set the error message, but also to remove it when no error condition exists.
An ErrorProvider has these additional advantages over other error-display techniques.
- If you used a pop-up dialog box the message will disappear when the user clicks "OK" and it would require specific coding to make it reappear. The ErrorProvider automatically redisplays the error whenever users wish.
- If you used a single TextBox or Label control to display error messages (thereby retaining it longer than a pop-up dialog) you could persist only a single error message; for forms with multiple errors each additional error would supplant the previous error. An ErrorProvider automatically provides both display and persistence for as many error messages as you have Controls on your form.
- Adding a dedicated TextBox or Label control for each validated control is a possible solutionyou can make each visible only when required to display an error message. In fact, that's even marginally better than the ErrorProvider because users don't have to use the mouse to display each error, but it also requires you to create and maintain considerably more UI code, not to mention the form real estate and resources that all these TextBoxes and Labels would require.