Page 1 of 1

Creating a CheckBoxList validation control in C#

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1633
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Post icon  Posted 06 May 2008 - 03:01 PM

Welcome to my tutorial on creating a CheckBoxList Validation control in C#. I created this control simply because there isn't one in the .Net Framework, and unlike the RadioButtonList, you cannot use a RequiredFieldValidator Control on it. Like all other validation controls in the .Net Framework our control inherits the BaseValidator Class, which automatically gives us access to all methods, properties and events of this class. This control is also for a web based application, but with some modifications could be ported for a Windows application.

This class library consists of two class files, the CBLValidator class and the ControlConverter Class. The ControlConverter Class inherits from the StringConverter Class, which allows us to pass the name of the control to validate as a string and convert it to a Control object.

This class consists of two methods, both of which are marked with the override modifier, which allows us to override this base method to fit our needs. The first method is the GetStandardValuesSupported(ITypeDescriptorContext). We override this method to simply return true.

As with any class we create in .Net we need to make sure we have a reference to the proper Namespaces, for this class we use


using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;



Now lets take a look at the two methods in this class


/// <summary>
/// Checks the page context to see if standard values are supported.
/// </summary>
/// <param name="context">The web page's context object.</param>
/// <returns>A boolean true/false value.</returns>
/// <remarks></remarks>
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
    return true;
}




The 2nd method is the GetStandardValues(ITypeDescriptorContext) Method, which we override to gather all the items in the CheckBoxList Control we are validating and add them to an ArrayList


/// <summary>
/// Parses the page context and finds all CheckBoxList IDs.
/// </summary>
/// <param name="context">The web page's context object.</param>
/// <returns>A StandardValuesCollection of CheckBoxList IDs.</returns>
/// <remarks></remarks>
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
    ArrayList cblArray = new ArrayList();
    foreach (Control control in context.Container.Components)
    {
        try
        {
            if (object.ReferenceEquals(control.GetType(), typeof(CheckBoxList)))
            {
                if (control.ID.StartsWith("_ctl"))
                {
                    cblArray.Add(control.ID.Remove(1, control.ID.ToString().IndexOf('_', 1) + 1));
                }
                else
                {
                    cblArray.Add(control.ID);
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    return new StandardValuesCollection(cblArray);
}




We use this class when we set the ControlToValidate Property of our CBLValidator control, so now lets take a look at that class. As with any class we need to ensure we have a reference to the proper Namespaces, in this class we use the following Namespaces:


using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;




Properties

Our validation control consists of five Properties:
  • MinRequired: Minimum number of items that are required to be selected in the control being validated
  • MaxAllowed: Maximum number of items that can be selected in the control being validated (Set to zero to allow all items to be selected)
  • ControlPropertiesValid: Determines if the control specified in the ControlToValidate property is a valid control
  • ControlToValidate: The control we are validating.

So lets take a look at these properties:

MinRequired:

/// <summary>
/// The minimum number of checkboxes allowed to be checked.
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
[System.ComponentModel.Description("The minimum number of checkboxes allowed to be checked.")]
public Int32 MinRequired
{
    get
    {
        try
        {
            int num = 0;
            if (Int32.TryParse(ViewState["MinimumCheckBoxesRequired"].ToString(), out num))
            {
                return num;
            }
            else
            {
                return 1;
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
    set
    {
        try
        {
            ViewState["MinRequired"] = value;
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
}




MaxAllowed

/// <summary>
/// The maximum number of checkboxes allowed to be checked. Set this to zero to allow all.
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
[System.ComponentModel.Description("The maximum number of checkboxes allowed to be checked. Set this to zero to allow all.")]
public Int32 MaxAllowed
{
    get
    {
        try
        {
            Int32 num = 0;
            Int32.TryParse(ViewState["MaxAllowed"].ToString(), out num);
            return num;
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
    set
    {
        try
        {
            ViewState["MaximumCheckBoxesAllowed"] = value;
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
}




ControlToValidate

/// <summary>
/// Gets or sets the CheckBoxList to validate.
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
[System.ComponentModel.Description("Gets or sets the CheckBoxList to validate."), System.ComponentModel.TypeConverter(typeof(ControlConverter))]
public new string ControlToValidate
{
    get
    {
        try
        {
            object control = ViewState["ControlToValidate"];
            if (control == null)
            {
                return string.Empty;
            }
            else
            {
                return control.ToString();
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
    set
    {
        try
        {
            ViewState["ControlToValidate"] = value;
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
}




ControlPropertiesValid

protected override bool ControlPropertiesValid()
{
    try
    {
        return true;
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}




Methods

Our control consists of four (4) methods:

  • EvaluateIsValid: Method to determine if validation was successful
  • EvaluateIsChecked: Method to determine is the proper number of items are selected
  • OnPreRender: Method that adds our client-side validation code to the control before it is rendered
  • BuildValidation: This is the method that creates our client-side validation code

Now lets take a look at each of these methods:


EvaluateIsValid

/// <summary>
/// method to determine if the validation failed or succeeded
/// </summary>
/// <returns></returns>
protected override bool EvaluateIsValid()
{
    try
    {
        return EvaluateIsChecked();
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}




EvaluateIsChecked

/// <summary>
/// Server side code to check that the required number of checkboxes are checked.
/// </summary>
/// <returns>A boolean value </returns>
/// <remarks></remarks>
protected bool EvaluateIsChecked()
{
    try
    {
        //get the control to validate
        CheckBoxList list = null;
        list = (CheckBoxList)this.FindControl(this.ControlToValidate);

        //initialize items checked to zero
        Int32 count = 0;

        //count each selected item
        foreach (ListItem item in list.Items)
        {
            if (item.Selected)
            {
                count += 1;
            }
        }

        //make sure it falls within MinRequired and MaxAllowed
        if (count >= MinRequired & (count <= MaxAllowed | MaxAllowed == 0))
        {
            //if it's in the range return true
            return true;
        }
        //otherwise return false
        return false;
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}




OnPreRender

/// <summary>
///adds our client-side validation code to the control
/// </summary>
/// <param name="e"></param>
/// <remarks>
///checks first to make sure the control has EnableClientScript enabled 
///</remarks>
protected override void OnPreRender(EventArgs e)
{
    try
    {
        //check and see if client script is enabled for the control
        if (EnableClientScript)
        {
            //build our validation script
            BuildValidation();
        }
        //pre-render the control
        base.OnPreRender(e);
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}




BuildValidation

/// <summary>
/// method for building the validation code for the ChecKBoxList control
/// we wish to validate
/// </summary>
/// <remarks></remarks>
protected void BuildValidation()
{
    try
    {
        ClientScriptManager manager = this.Page.ClientScript;
        Type type = this.GetType();

        if (!(manager.IsClientScriptBlockRegistered(type, "StartVerification" + this.ClientID)))
        {
            this.Attributes.Add("evaluationfunction", "start_verification_" + this.ClientID);
            StringBuilder builder = new StringBuilder();
            builder.Append("<script language=\"javascript\">" + Environment.NewLine);
            builder.Append("<!--" + Environment.NewLine);
            builder.Append("function start_verification_" + this.ClientID + "(val) {" + Environment.NewLine);
            builder.AppendFormat("\t");
            builder.Append("return checkboxlist_verification('" + this.ClientID + "');" + Environment.NewLine);
            builder.Append("}" + Environment.NewLine);
            builder.Append("-->" + Environment.NewLine);
            builder.Append("</script>" + Environment.NewLine);

            if (ScriptManager.GetCurrent(this.Page) == null)
            {
                manager.RegisterClientScriptBlock(type, "StartVerification" + this.ClientID, builder.ToString());
            }
            else
            {
                ScriptManager.RegisterClientScriptBlock(this.Page, typeof(Page), "StartVerification" + this.ClientID, builder.ToString(), false);
            }
        }

        if (!(manager.IsClientScriptBlockRegistered(type, "CheckBoxListVerification" + this.ClientID)))
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("<script language=\"javascript\">" + Environment.NewLine);                    
            builder.Append("<!--" + Environment.NewLine);
            builder.Append("function checkboxlist_verification(clientID) {" + Environment.NewLine);
            builder.AppendFormat("\t");
            builder.Append("var val = document.all[document.all[clientID].controltovalidate];" + Environment.NewLine);
            builder.AppendFormat("\t");
            builder.Append( "var col = val.all;" + Environment.NewLine);
            builder.AppendFormat("\t");
            builder.Append("if (col != null ) {" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("var checked = 0;" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("var checkboxcount = 0;" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("for (i = 0; i < col.length; i++ ) {" + Environment.NewLine);
            builder.AppendFormat("\t\t\t");
            builder.Append("if (col.item(i).tagName == 'INPUT') {" + Environment.NewLine);
            builder.AppendFormat("\t\t\t\t");
            builder.Append("checkboxcount += 1;" + Environment.NewLine);
            builder.AppendFormat("\t\t\t\t");
            builder.Append("if (col.item(i).checked ) {" + Environment.NewLine);
            builder.AppendFormat("\t\t\t\t\t");
            builder.Append("checked += 1;" + Environment.NewLine);
            builder.AppendFormat("\t\t\t\t");
            builder.Append("}" + Environment.NewLine);
            builder.AppendFormat("\t\t\t");
            builder.Append("}" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("}" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("if (checked >= " + MinRequired + " && (checked <= " + MaxAllowed + " || " + MaxAllowed + " == 0))" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("{" + Environment.NewLine);
            builder.AppendFormat("\t\t\t");
            builder.Append("DOMCall(cbxAll).checked = false;" + Environment.NewLine);
            builder.AppendFormat("\t\t\t");
            builder.Append("return true;" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("}" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("else {" + Environment.NewLine);
            builder.AppendFormat("\t\t\t");
            builder.Append("return false;" + Environment.NewLine);
            builder.AppendFormat("\t\t");
            builder.Append("}" + Environment.NewLine);
            builder.AppendFormat("\t");
            builder.Append("}" + Environment.NewLine);
            builder.Append("}" + Environment.NewLine);
            builder.Append("-->" + Environment.NewLine);
            builder.Append("</script>" + Environment.NewLine);

            if (ScriptManager.GetCurrent(this.Page) == null)
            {
                manager.RegisterClientScriptBlock(type, "CheckBoxListVerification" + this.ClientID, builder.ToString());
            }
            else
            {
                ScriptManager.RegisterClientScriptBlock(this.Page, typeof(Page), "CheckBoxListVerification" + this.ClientID, builder.ToString(), false);
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}




You will notice that the bulk of the work is done in the BuildValidation method, this is where the code for validating the control is created.

Well there you have it, a custom control to validate a CheckBoxList Control. I have, since creating it, found this control to be an invaluable addition to my code library, and I use it often. I hope you have found this tutorial useful and informative. Next I will port this same control for a Windows application and create a tutorial for it as well. Thanks for reading.

Happy Coding!

Is This A Good Question/Topic? 0
  • +

Replies To: Creating a CheckBoxList validation control in C#

#2 cforsyth  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 10-September 08

Posted 10 September 2008 - 06:24 PM

Thanks for writing this article, you've helped me a great deal.
Was This Post Helpful? 0
  • +
  • -

#3 miomao  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 14-January 09

Posted 15 January 2009 - 02:39 AM

Remember to add Assembly: System.Web.Extensions (in System.Web.Extensions.dll) to your project.
Was This Post Helpful? 0
  • +
  • -

#4 Tweet  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 04-December 09

Posted 04 December 2009 - 09:39 AM

Thanks very much for this - I managed to get it working, although there were a few issues, eg...

1. The ViewState properties did not match between the getter and setter for MinRequired and MaxAllowed properties.
2. The javascript for client-side validation only worked on IE.

So, I've adapted the CBLValidator class as below. This should hopefully work with all major browsers. It should also only creates a single javascript function per page, even if you have multiple CheckBoxLists that you're validating (note the addition of AddAttributesToRender()).

public class CheckBoxListValidator : BaseValidator
	{
		private const string ClientScriptKey = "CheckBoxListValidatorEvaluateIsValid";

		/// <summary>
		/// The minimum number of checkboxes allowed to be checked.
		/// </summary>
		/// <value></value>
		/// <returns></returns>
		/// <remarks></remarks>
		[System.ComponentModel.Description("The minimum number of checkboxes allowed to be checked.")]
		public Int32 MinRequired
		{
			get
			{				
				int num = 0;				
				if (Int32.TryParse(ViewState["MinimumCheckBoxesRequired"].ToString(), out num))
				{
					return num;
				}
				else
				{
					return 1;
				}				
			}
			set
			{
				ViewState["MinimumCheckBoxesRequired"] = value;
			}
		}

		/// <summary>
		/// The maximum number of checkboxes allowed to be checked. Set this to zero to allow all.
		/// </summary>
		/// <value></value>
		/// <returns></returns>
		/// <remarks></remarks>
		[System.ComponentModel.Description("The maximum number of checkboxes allowed to be checked. Set this to zero to allow all.")]
		public Int32 MaxAllowed
		{
			get
			{				
				int num = 0;
				Int32.TryParse(ViewState["MaximumCheckBoxesAllowed"].ToString(), out num);
				return num;
			}
			set
			{				
				ViewState["MaximumCheckBoxesAllowed"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the CheckBoxList to validate.
		/// </summary>
		/// <value></value>
		/// <returns></returns>
		/// <remarks></remarks>
		[System.ComponentModel.Description("Gets or sets the CheckBoxList to validate."), System.ComponentModel.TypeConverter(typeof(ControlConverter))]
		public new string ControlToValidate
		{
			get
			{
				object control = ViewState["ControlToValidate"];
				if (control == null)
				{
					return string.Empty;
				}
				else
				{
					return control.ToString();
				}
			}
			set
			{
				ViewState["ControlToValidate"] = value;
			}
		}

		protected override bool ControlPropertiesValid()
		{
			return true;
		}

		/// <summary>
		/// method to determine if the validation failed or succeeded
		/// </summary>
		/// <returns></returns>
		protected override bool EvaluateIsValid()
		{
			return EvaluateIsChecked();
		}

		/// <summary>
		/// Server side code to check that the required number of checkboxes are checked.
		/// </summary>
		protected bool EvaluateIsChecked()
		{
			//get the control to validate
			CheckBoxList list = null;
			list = (CheckBoxList)this.FindControl(this.ControlToValidate);

			int count = 0;			
			foreach (ListItem item in list.Items)
			{
				if (item.Selected)
				{
					count++;
				}
			}

			//make sure it falls within MinRequired and MaxAllowed
			if (count >= MinRequired && (count <= MaxAllowed || MaxAllowed == 0))
			{				
				return true;
			}			
			return false;
		}

		/// <summary>
		/// Adds our client-side validation code to the control
		/// </summary>
		/// <param name="e"></param>
		/// <remarks>
		/// checks first to make sure the control has EnableClientScript enabled 
		///</remarks>
		protected override void OnPreRender(EventArgs e)
		{						
			if (EnableClientScript)
			{				
				BuildValidation();
			}			
			base.OnPreRender(e);
		}

		/// <summary>
		/// Add in the custom attributes
		/// </summary>
		/// <param name="writer"></param>
		protected override void AddAttributesToRender(HtmlTextWriter writer)
		{
			base.AddAttributesToRender(writer);
			Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "CheckBoxListValidatorEvaluateIsValid");			
			Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "minrequired", MinRequired.ToString());
			Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "maxallowed", MaxAllowed.ToString());			
		}
		
		/// <summary>
		/// Build the client-side validation code for checking CheckBoxList controls
		/// </summary>
		/// <remarks></remarks>
		protected void BuildValidation()
		{			
			ClientScriptManager manager = this.Page.ClientScript;
			Type type = this.GetType();

			if (!(manager.IsClientScriptBlockRegistered(type, ClientScriptKey)))
			{
				string jscript = @"
function CheckBoxListValidatorEvaluateIsValid(val) {	
	var minrequired = parseInt(val.minrequired);
	var maxallowed = parseInt(val.maxallowed);
	var chklist = document.getElementById(val.controltovalidate); 
	var inputs = chklist.getElementsByTagName('input');
	var checked = 0; 
	for(var i=0; i<inputs.length; i++) {
		if(inputs[i].getAttribute('type')=='checkbox') {
			if (inputs[i].checked)
			{
				checked++;
			}
		}
	}
	if (checked >= minrequired && (checked <= maxallowed || maxallowed == 0))
	{
		return true;
	}
	return false;
}
";
				if (ScriptManager.GetCurrent(this.Page) == null)
				{
					manager.RegisterClientScriptBlock(type, ClientScriptKey, jscript, true);
				}
				else
				{
					ScriptManager.RegisterClientScriptBlock(this.Page, typeof(Page), ClientScriptKey, jscript, true);
				}
			}
		}

	}


This post has been edited by Tweet: 04 December 2009 - 11:04 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1