Introduction
The ASP.Net Validator controls shipped by Microsoft .Net Framework (from 1.0 till 3.5) are very helpful for developers to implement form control validations, even for a novice developer with little knowledge on Javascript. However, it does lacks validators for some controls which are desperately needed for our day to day coding, say for instance CheckBox, CheckBoxList, etc. This article describes how to develop your own validator controls to validate any .net server controls with your own logics. Or broadly, how to extend a BaseValidator class with custom functionality?
Background
Required Field Validators are very popular among the .net validator controls. They works like a charm for Textbox, Dropdowns, FileUpload, etc. While writing any web form, say a feedback form or a registration form, we may have to use CheckBoxList controls to enable the user to ope multiple items from the list display. Here is the catch22. We dont have the validator...!. Instead, we should either write a lengthy code in javascript for client validation or use the Custom Validator Control to enable the validations in both the ends (server and client). User have another option to make use of partial rendering of pages for validation by using Ajax update panels control. However the later approach is troublesome and time consuming and is fully based on our host and network. Th built in validators are not allowed to be assigned for validation to any other controls like CheckBox since the ValidatedControlConverter will list only those webcontrols which can be validated. When creating your own validation control, you can enable the designer to display a list of controls that support validation controls.
Which Controls Can Be Validated?
In order to be referenced by a validation control, a control must have a validation property. All controls that can be validated have a ValidationPropertyAttribute, which indicates which property should be read for the purposes of validation. If you write your own control, you can make it take part in validation by providing one of these attributes to specify which property to use.
For validation to work client-side as well, this property must correspond to the value attribute of the HTML element that gets rendered on the client. Many complex controls such as DataGrid and Calendar do not have a value on the client and can only be validated on the server. This is why only controls that correspond closely to HTML elements can be involved in validation. Also, a control must have a single logical value on the client. This is why RadioButtonList can be validated, but CheckBoxList cannot.
Using the code
Every validators in .net is derived from the SuperClass BaseValidator. Hence it is the starting point. So while writing any validators for our use, we should derive our component from the BaseValidator to inherit all the default features of the validator controls.
public class RequiredFieldValidatorForCheckBoxList : BaseValidator
{
}
Now, we have to override the boolean function below to implement our logic to validate the control to be validated.
protected override bool ControlPropertiesValid()
{
if (this.ControlToValidate.Trim().Length == 0) return false;
Control ctrl = FindControl(ControlToValidate);
if ((ctrl == null) || (!(ctrl is < Type of Control to Validate, say CheckBox >))) return false; else return true;
}
Next step is to implement the logic to validate or invalidate the control. This is done by overriding the boolean function EvaluateIsValid() (as shown below)
protected override bool EvaluateIsValid()
{
eg:- If the control is not checked, return true else return false.
}
Next step is implement the OnLoad event of the control to throw exception if either the control is not valid or control is not selected properly.
protected override void OnLoad(EventArgs e)
{
if (logic == false)
{
throw new HttpException(string.Format("ControlToValidate of {0}
is either blank or not a valid CheckBoxList control", this.ID)));
}
else if{second logic == false)
{
}
}
Next is to enable listing of control in the design to be selected. Simply add an attribute to the string property that represents the control to validate, as follows:
[TypeConverter(typeof(ValidatedControlConverter))]
public string ControlToValidate
{
get
{
}
set
{
}
}
Next and final step is to implement the javascript to enable the client side validation. To do that, you have to create a StringBuilder object and write the complete Javascript function to validate the control in the browser and implement it in OnPreRender function.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if((ControlPropertiesValid()) && (this.EnableClientScript))
InjectClientValidationScript();
if (this.ErrorMessage.Trim().Length == 0)
this.ErrorMessage = this.ID;
}
private void InjectClientValidationScript()
{
StringBuilder sb_Script = new StringBuilder();
sb_Script.Append("<script language="\""javascript\">");
sb_Script.Append("\r");
sb_Script.Append("\r");
sb_Script.Append("function validate_CBL(sender) {");
sb_Script.Append("\r");
sb_Script.Append("var val =
document.getElementById(document.getElementById
(sender.id).controltovalidate);");
sb_Script.Append("\r");
sb_Script.Append("var col =
val.getElementsByTagName(\"*\");");
sb_Script.Append("\r");
sb_Script.Append("if ( col != null ) {");
sb_Script.Append("\r");
sb_Script.Append("for ( i = 0; i < col.length; i++ ) {");
sb_Script.Append("\r");
sb_Script.Append
("if (col.item(i).tagName == \"INPUT\"){");
sb_Script.Append("\r");
sb_Script.Append("if ( col.item(i).checked ) {");
sb_Script.Append("\r");
sb_Script.Append("\r");
sb_Script.Append("return true;");
sb_Script.Append("\r");
sb_Script.Append("}");
sb_Script.Append("\r");
sb_Script.Append("}");
sb_Script.Append("\r");
sb_Script.Append("}");
sb_Script.Append("\r");
sb_Script.Append("\r");
sb_Script.Append("\r");
sb_Script.Append("return false;");
sb_Script.Append("\r");
sb_Script.Append("}");
sb_Script.Append("\r");
sb_Script.Append("}");
sb_Script.Append("\r");
sb_Script.Append("</script>");
Page.ClientScript.RegisterClientScriptBlock
(GetType(), "SCRIPTBLOCK", sb_Script.ToString());
Page.ClientScript.RegisterExpandoAttribute
(ClientID, "evaluationfunction", "validate_CBL");
}
Points of Interest
Since we have derived our component from the BaseValidator class, our new control woul inherit all the default behaviour of the parent with zero effort. Care shoul only be taken to implement our logic to make it work. I have developed a control (ready to use) to validate CheckBoxList control. The control would exactly similiar way as other required field validator controls from Microsoft. It has a built in functionality to specify how many checkboxes to be ticked for a successfull validation. It is having a default value of 1 saying only one checkbox tick will successfully validate the control where as Zero represent all the items in the list is to be ticked for successfull validation.
You can download the fully functional copy of the control from http://znetcontrols.blogspot.com/2008/08/required-field-validator-for.html. The control is tested both in IE as well as FireFox browsers and it is working great!
References
Article by Scott Mitchell - http://aspnet.4guysfromrolla.com/articles/092006-1.aspx
History
The above control is added in the same control library what i have developed previously and now it has two controls, GridView with grouping and record indexing and RequiredFieldValidator for CheckBoxList control