Creating Validator Controls for the CheckBox and CheckBoxListBy Scott Mitchell
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
ControlToValidateproperty to the
IDof 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
BaseValidatorclass (found in the
System.Web.UI.WebControlsnamespace). Not surprisingly, all of the built-in ASP.NET validation controls extends the
BaseValidatorclass, 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 only
BaseValidatorclass 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 the
BaseValidatorclass, it checks to ensure that the
ControlToValidateproperty 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 if
ControlToValidateis set to the
IDof a CheckBox or CheckBoxList.
AddAttributesToRender(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's
EnableClientScriptproperty is True (the default).
CheckBoxListValidatorclasses. In the
CheckBoxValidatorclass, we'll add a
MustBeCheckedproperty that indicates whether the CheckBox needs to be checked or unchecked to be considered valid. In the
MinimumNumberOfSelectedCheckBoxesproperty 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
CheckBoxListValidatorclasses I added a protected helper property to return a reference to the control being validated. Typically, the
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
CheckBoxValidatorclass's helper property and
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
ControlPropertiesValid() method, which is responsible for insuring that the essential validation control
properties are set and are valid, starts by checking the
property. If it's not specified, an
HttpException is thrown. Likewise, if it cannot find a control with
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.
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
BaseValidatorclass 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
MustBeCheckedproperty 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
OnPreRender(EventArgs) method, whereas the name of the validation function and any additional
propeties are added in the
Let's start with the
OnPreRender(EventArgs) method. The following code starts by calling the base class's
OnPreRender(EventArgs) method, which injects the common client-side script.
method is used to add a script include (
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.)
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:
ID of the control being validated is available via the
controltovalidate property of the
passed-in object; a call to the
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
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
this (and other) information. For example, a RequiredFieldValidator has a select set of its properties rendered in client-side
script like so:
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
This information is injected into the page's rendered markup via the validation control's
method, and can be injected in two ways:
- Using the
AddAttributemethod of the passed-in
HtmlTextWriterobject. 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.
BaseValidatorclass 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
Helpersclass. 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
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.
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
skmValidatorsassembly into your application's
/Binfolder. 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.