Creating Validator Controls for the CheckBox and CheckBoxList
By Scott Mitchell
Introduction
ASP.NET provides a variety of validation Web controls that can be used to validate a user's form field inputs. (See Form Validation with ASP.NET - It Doesn't Get Any Easier! for general information on the validation Web controls and Dissecting Validation Controls in ASP.NET 2.0 for the validation control changes from ASP.NET version 1.x to ASP.NET version 2.0.) Unfortunately, the validation Web controls do not work with the CheckBox or CheckBoxList Web controls. If you set a validation control's
ControlToValidate
property to the ID of a CheckBox or CheckBoxList, the page will throw an HttpException, stating:
"Control 'controlID' referenced by the ControlToValidate property of 'validationControlID' cannot be validated."
There may be times, however, when you need to provide validation for a CheckBox or CheckBoxList. Many Web pages with Terms of Service include a CheckBox titled "I agree to the above terms" that must be checked before continuing. Likewise, a Web Form may contain a set of options in the form of a CheckBoxList. Perhaps the user is required to check at least one of these options before continuing. To provide such validation, we have three choices:
- Forgo any sort of validation Web control semantics and perform the validation check using code on postback. The downside of this is that it breaks from the standard validation control metaphor and requires extra effort to include client-side validation.
- Use the CustomValidator control and define our own server-side and client-side validation logic. The benefit of this approach is that it adheres to the validation control metaphor; however, the validation logic is tightly bound to the ASP.NET page, meaning that the server-side and client-side validation must be replicated on all pages that need to validate a CheckBox or CheckBoxList. (See Using the CustomValidator Control for more information on this topic.)
- Create a custom, compiled validation server control that provides the functionality needed. The benefit of this approach is that we have a reusable, easily deployable custom server control that adheres to the validation control metaphor. Unfortunately, this option requires the most upfront code/effort.
The server controls provided in this article were designed using Visual Studio 2005 and the .NET Framework 2.0's base class libraries; consequently, they will only work in ASP.NET 2.0 applications. If you are still using ASP.NET 1.x, check out Creating a Validation Control for CheckBoxLists. Alternatively, you may adapt the code presented here to work in ASP.NET 1.x.
| Creating CheckBox and CheckBoxList Validators in ASP.NET 1.x |
|---|
| The server controls examined in this article were designed using Visual Studio 2005 and the .NET Framework 2.0's base class libraries; consequently, they will only work in ASP.NET 2.0 applications. If you are still using ASP.NET 1.x, check out Creating a Validation Control for CheckBoxLists. Alternatively, you may adapt the code presented here to work in ASP.NET 1.x. |
Understanding the ASP.NET Validation Workflow
A validation control's primary responsibility is to determine whether or not its assigned control's value is valid. What constitutes validity depends on the validation control - a RequiredFieldValidator, for example, checks to ensure that its control's current value doesn't equal the specified
InitialValue. Secondarily, validation controls
can be grouped into validation groups, be validated through client script, and so on. Many of these requirements are
provided by properties and methods in the BaseValidator
class (found in the System.Web.UI.WebControls namespace). Not surprisingly, all of the built-in ASP.NET
validation controls extends the BaseValidator class, adding their own customizations.
In a short while we'll create our own custom validation Web controls for validating a CheckBox and CheckBoxList. These custom
classes will inherit the BaseValidator class, overriding the following methods:
EvaluateIsValid()- this is the onlyBaseValidatorclass that must be overridden. It returns a Boolean value that indicates the validation control's validity.ControlPropertiesValid()- this method returns a Boolean indicating if the control being validated is one that can be. In theBaseValidatorclass, it checks to ensure that theControlToValidateproperty is set and that the control referenced has a property that can be validated. We need to override this method because this method is the one that throws an exception ifControlToValidateis set to theIDof a CheckBox or CheckBoxList.OnPreRender(EventArgs)andAddAttributesToRender(HtmlTextWriter)- these methods inject client-side script to perform client-side validation (if the user is visiting with an uplevel browser and the validation control'sEnableClientScriptproperty is True (the default).
CheckBoxValidator and CheckBoxListValidator
classes. In the CheckBoxValidator class, we'll add a MustBeChecked property that indicates whether
the CheckBox needs to be checked or unchecked to be considered valid. In the CheckBoxListValidator class, the
MinimumNumberOfSelectedCheckBoxes property indicates the least number of CheckBoxList items that must be selected
for validity. Both controls provide client-side validation support.
The remainder of this article examines the CheckBoxValidator control in detail (the CheckBoxListValidator control is not discussed in this article, but is included in the code available at the end of this download).
The Core CheckBoxValidator Custom Validation Control Members
In both the
CheckBoxValidator and CheckBoxListValidator classes I added a protected helper property
to return a reference to the control being validated. Typically, the BaseValidator class's
GetControlValidationValue()
method can be referenced to get back the value being validated, but with a CheckBox or CheckBoxList, a call to this method
will throw an HttpException. Therefore, the control value is accessed through the helper property. The following
code shows the CheckBoxValidator class's helper property and ControlPropertiesValid() and
EvaluateIsValid() methods:
namespace skmValidators
|
First, note that the CheckBoxValidator class extends the BaseValidator class. Next, examine the
CheckBoxToValidate property. It uses the FindControl("controlID") method to find the
control with the specified ControlToValidate value. If no control with that ID is found, or if
it's not a CheckBox, the property returns null.
The ControlPropertiesValid() method, which is responsible for insuring that the essential validation control
properties are set and are valid, starts by checking the ControlToValidate
property. If it's not specified, an HttpException is thrown. Likewise, if it cannot find a control with
the specified ControlToValidate or if that control is not a CheckBox, an HttpException is thrown.
If those two checks pass, then the method returns True, indicating that the control properties are valid.
The EvaluateIsValid() method is invoked whenever the validation control's validity needs to be determined.
This method returns True - indicating validity - only if the CheckBox to validate's Checked property is set
as dictated by the MustBeChecked property. That is, if MustBeChecked is True, the CheckBoxValidator
control returns True only if its CheckBox is checked; conversely, if MustBeChecked is False, the CheckBox must
be unchecked for the validation control to indicate validity.
Adding Client-Side Validation Support
At this point, we have all of the needed server-side functionality for the CheckBoxValidator control. To add client-side functionality, however, we must add a bit more code. The
BaseValidator class automatically adds client-side
script for handling the plumbing of client-side validation: performing validation when the form submits, determining what
client-side function to invoke for validating each validator, and so on. All we need to do is inject the client-side function
that performs the validation, specify the client-side validation function to invoke, and add any properties needed for
client-side validation to the page's rendered markup (for the CheckBoxValidator control, we need to persist the value of
the MustBeChecked property to the page's rendered markup to indicate whether the CheckBox needs to be checked
or unchecked to be valid).
These two tasks are handled in two separate methods. The client-side script used for validation should be injected in
the OnPreRender(EventArgs) method, whereas the name of the validation function and any additional
propeties are added in the AddAttributesToRender(HtmlTextWriter) method.
Let's start with the OnPreRender(EventArgs) method. The following code starts by calling the base class's
(BaseValidator's) OnPreRender(EventArgs) method, which injects the common client-side script.
Next, the RegisterClientScriptInclude()
method is used to add a script include (<script src="urlToScript" ... />) to the JavaScript
file embedded within the CheckBoxValidator class's assembly. (Embedding resources is an easy and efficient means
of deploying and referencing external resource files with a server control library; see Accessing
Embedded Resources through a URL using WebResource.axd for more information.)
EvaluateIsValid() methods:
namespace skmValidators
|
The client-side validation function must accept a single input parameter (a reference to the validation control) and must return a Boolean value indicating the validity of the validation control. This function for the CheckBoxValidator control is blindingly simple:
function CheckBoxValidatorEvaluateIsValid(val)
|
The ID of the control being validated is available via the controltovalidate property of the
passed-in object; a call to the document.getElementById("id")
function returns a reference to the actual control. The mustBeChecked property of the validation control
is then accessed. Finally, the function returns True only if the control's checked property matches up to the
mustBeChecked property value.
At this point there are two questions facing us. First, how does the common script injected by the BaseValidator know
to call the CheckBoxValidatorEvaluateIsValid function to validate the CheckBoxValidator control? And second,
how is the MustBeChecked property value specified for the CheckBoxValidator control passed to this client-side
function? If you do a View/Source of a page with validation controls on it, you'll find a JavaScript section that spells out
this (and other) information. For example, a RequiredFieldValidator has a select set of its properties rendered in client-side
script like so:
var RequiredFieldValidator1 = document.all ? document.all["RequiredFieldValidator1"] : document.getElementById("controlID");
|
There may be more settings there, depending on what properties you've set for the RequiredFieldValidator, but the concept is the
same - property values needed by the client-side validation logic must be persisted to the client-side through the page's
rendered markup. This includes, at minimum, the ID of the control to validate and the function responsible for
validation.
This information is injected into the page's rendered markup via the validation control's AddAttributesToRender(HtmlTextWriter)
method, and can be injected in two ways:
- Using the
AddAttributemethod of the passed-inHtmlTextWriterobject. This adds attributes to the validation Web control's rendered HTML element. - Using the
RegisterExpandoAttributemethod, which adds the attributes using client-side script, like in the RequiredFieldValidator script block shown above.
BaseValidator class adds some of the control's needed state automatically (such as the controltovalidate)
and chooses which method to use based on the page's XHTML conformance settings. The logic used to determine these settings are,
unfortunately, internal, meaning that they cannot be called from an assebly outside of the .NET Framework. I've attempted to
do my best to replicate the logic in a Helpers class. The reason this matters is because, in my testing, I found
that for some browsers it was essential that the properties all be defined the same way. Internet Explorer was happy to have
some properties defined using the expando approach, and others as inline attributes, but FireFox wouldn't recognize the inline
attribute values when other values were specified using the expando technique.
Enough minutia, let's look at the code! As you can see below, two attributes are added (either via the expando or AddAttribute
approaches, depending on the Helpers.EnableLegacyRendering() method's return value). The first attribute is required
and specifies the name of the function to invoke to perform client-side validation. The second attribute persists the
MustBeChecked property to the rendered output.
namespace skmValidators
|
Using the CheckBoxValidator and CheckBoxListValidator Controls
To get started using the CheckBoxValidator and CheckBoxListValidator controls in your ASP.NET 2.0 web application, download the code at the end of this article and drop the
skmValidators assembly into your application's /Bin
folder. You can add the validation controls to Visual Studio 2005's Toolbox - right click on the Toolbox, select Choose Items
and browse to skmValidators.dll - or you can manually add the controls using declarative markup and the
<%@ Register %gt; directive.
Once you've added the controls to the Toolbox or have entered their markup manually, they should appear as any validation control when in the Designer. Moreover, their properties should be accessible through the Properties window. And most importantly, when visiting a page through a browser, they should function as expected!
The CheckBoxValidator in the Designer in Visual Studio
The CheckBoxValidator When Viewed Through a Web Page
At the end of this article you'll find links to related articles, the complete project code that includes a test project with a demo page. In this article we only examined the CheckBoxValidator control; the download includes an additional validation control designed to work with CheckBoxLists.
| The CheckBoxValidator Control Has Been Upgraded! |
|---|
|
I have upgraded the CheckBoxValidator so that it can optionally enable or disable an associated Button, LinkButton, or ImageButton control depending
on its CheckBox's checked state.
For more information, see Disabling the Submit Button Until a CheckBox is Checked. |
Happy Programming!
Further Readings:
WebResource.axd
Attachments



