:::: MENU ::::

Friday, October 24, 2008

The BaseValidator class defines the basic implementation needed for all Validation controls. There are 6 Validation Controls included in the ASP.NET 2.0 and ASP.NET 3.5 framework which validate controls to prevent the users from entering wrong data. However, there are a few shortcomings in these controls. The good part is that ASP.NET provides the framework to create new validation controls. If you would like to create your own validation control, you can do so by deriving a new control from the BaseValidator abstract class. In this article, we will explore how to create a custom validation control in ASP.NET and provide both Server and Client Side Validation for the same.

 

Step 1: Create an ASP.NET Website (File > New > Website). Drag and drop a CheckBoxList, RadioButtonList and a Button control on to the page.

 

Step 2: Let us first complete the task of populating the CheckBoxList and RadioButtonList  controls in the Page_Load event as shown below:

C#

 

protected void Page_Load(object sender, EventArgs e)

{

    if (!Page.IsPostBack)

    {

        List<string> lstStr = new List<string>();

        lstStr.Add("Item 1");

        lstStr.Add("Item 2");

        lstStr.Add("Item 3");

        lstStr.Add("Item 4");

        CheckBoxList1.DataSource = lstStr;

        CheckBoxList1.DataBind();

        RadioButtonList1.DataSource = lstStr;

        RadioButtonList1.DataBind();           

    }

}

VB.NET

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If (Not Page.IsPostBack) Then

            Dim lstStr As List(Of String) = New List(Of String)()

            lstStr.Add("Item 1")

            lstStr.Add("Item 2")

            lstStr.Add("Item 3")

            lstStr.Add("Item 4")

            CheckBoxList1.DataSource = lstStr

            CheckBoxList1.DataBind()

            RadioButtonList1.DataSource = lstStr

            RadioButtonList1.DataBind()

        End If

    End Sub

 

Step 3: Our next step would be to create the custom validation control. But before that, let us quickly take an overview of what we are trying to achieve. This sample will demonstrate that the user should select at least one checkbox and one radiobutton before submitting the form to the server. For this purpose, we will first show how to create a custom validation control to perform server-side validation and then extend the control to support client-side validation too.

Note: If you are wondering why we have chosen to create a custom validation control instead of using a CustomValidator, then I would state that the main reason for doing so is ‘reusability’. You would soon see that we will be using the same custom validation control to validate both the CheckBoxList as well as RadioButtonList. It is as simple as registering the assembly and start using it.

 

Step 4: To create our custom validation control, Right click the project > Add New Item > From the Template, choose ‘Class’ > Rename the class to ‘ListValidator’ or anything you like > Choose the Language (C# or VB) > Click on Add.

Note: Visual Studio would prompt you to add the class to the App_Code. Choose yes to do so.

 

Step 5: As already discussed, we will be deriving from the BaseValidator abstract class. You will need to implement the ‘EvaluateIsValid’ method which returns a Boolean value indicating if the field/control being validated is valid or not. The code for the server side validation will be similar to the following:

 

Server-Side Validation

C#

namespace CustomListValidator

{

///<summary>

/// Summary description for ListValidator

///</summary>

public class ListValidator : BaseValidator

{

    public ListValidator()

    {

 

    }

 

    protected override bool ControlPropertiesValid()

    {

        Control ctrl = FindControl(ControlToValidate) as ListControl;

        return (ctrl != null);

    }

 

    protected override bool EvaluateIsValid()

    {

        return this.CheckIfItemIsChecked();

    }

 

    protected bool CheckIfItemIsChecked()

    {

        ListControl listItemValidate = ((ListControl)this.FindControl(this.ControlToValidate));

        foreach (ListItem listItem in listItemValidate.Items)

        {

            if (listItem.Selected == true)

                return true;

        }

        return false;

    }

 

}

}

VB.NET

Namespace CustomListValidator

    ''' <summary>

    ''' Summary description for ListValidator

    ''' </summary>

    Public Class ListValidator

        Inherits BaseValidator

        Public Sub New()

 

        End Sub

 

        Protected Overrides Function ControlPropertiesValid() As Boolean

            Dim ctrl As Control = TryCast(FindControl(ControlToValidate), ListControl)

            Return (Not ctrl Is Nothing)

        End Function

 

        Protected Overrides Function EvaluateIsValid() As Boolean

            Return Me.CheckIfItemIsChecked()

        End Function

 

        Protected Function CheckIfItemIsChecked() As Boolean

            Dim listItemValidate As ListControl = (CType(Me.FindControl(Me.ControlToValidate), ListControl))

            For Each listItem As ListItem In listItemValidate.Items

                If listItem.Selected = True Then

                    Return True

                End If

            Next listItem

            Return False

        End Function

    End Class

End Namespace

In the code snippet shown above, we override the EvaluateIsValid() method. The ‘ControlToValidate’ is cast to a ListControl, which is an abstract base class for all list-type controls. We then loop through all the ListItems and if one of the items in both the CheckBoxList as well as RadioButtonList is checked by the user, we return true, else we return false.

In order to use this custom validation control on the CheckBoxList and RadioButtonList kept in our page, we will use the <%@ Register %> directive as shown below:

<%@ Register TagPrefix="CLV" Namespace="CustomListValidator" %>

<div>

<asp:CheckBoxList ID="CheckBoxList1" runat="server">

</asp:CheckBoxList></div>

        <CLV:ListValidator runat="server" ID="custLstVal" ControlToValidate="CheckBoxList1" ErrorMessage="At least one item in the checkboxlist should be checked" />

 

<asp:RadioButtonList ID="RadioButtonList1" runat="server">

</asp:RadioButtonList>

        <CLV:ListValidator runat="server" ID="custRadVal" ControlToValidate="RadioButtonList1" ErrorMessage="At least one item in the radiobuttonlist should be checked" />

<br />

<br />

<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />

As you will observe, the two controls are being validated by the same custom validation control that we are building. Run the application and click on the button without checking any items in the two controls. Two error messages are displayed when the form is submitted.

 

Step 6: We saw how to perform server side validation. Let us see how we can now perform validation directly on the client side, without a postback. To perform client side validation, you would need to override OnPreRender and create the javascript function using a StringBuilder object and output it using Page.ClientScript.RegisterClientScriptBlock().

Client-Side Validation

The code with the OnPreRender and JavaScript function will look similar to the following. This code is to be added in the same class where the server-side validation code was added.

 

C#

protected override void OnPreRender(EventArgs e)

{

    // Determines whether the validation control can be rendered

    // for a newer ("uplevel") browser.

    // check if client-side validation is enabled.

    if (this.DetermineRenderUplevel() && this.EnableClientScript)

    {

        Page.ClientScript.RegisterExpandoAttribute(this.ClientID, "evaluationfunction", "CheckIfListChecked");

        this.CreateJavaScript();

    }

    base.OnPreRender(e);

}

 

protected void CreateJavaScript()

{

    StringBuilder sb = new StringBuilder();

    sb.Append(@"<script type=""text/javascript"">function CheckIfListChecked(ctrl){");

    sb.Append(@"var chkBoxList = document.getElementById(document.getElementById(ctrl.id).controltovalidate);");

    sb.Append(@"var chkBoxCount= chkBoxList.getElementsByTagName(""input"");");

    sb.Append(@"for(var i=0;i<chkBoxCount.length;i++){");

    sb.Append(@"if(chkBoxCount.item(i).checked){");

    sb.Append(@"return true; }");

    sb.Append(@"}return false; ");

    sb.Append(@"}</script>");

    Page.ClientScript.RegisterClientScriptBlock(GetType(),"JSScript", sb.ToString());

}

VB.NET

        Protected Overrides Sub OnPreRender(ByVal e As EventArgs)

            ' Determines whether the validation control can be rendered

            ' for a newer ("uplevel") browser.

            ' check if client-side validation is enabled.

            If Me.DetermineRenderUplevel() AndAlso Me.EnableClientScript Then

                Page.ClientScript.RegisterExpandoAttribute(Me.ClientID, "evaluationfunction", "CheckIfListChecked")

                Me.CreateJavaScript()

            End If

            MyBase.OnPreRender(e)

        End Sub

 

        Protected Sub CreateJavaScript()

            Dim sb As StringBuilder = New StringBuilder()

            sb.Append("<script type=""text/javascript"">function CheckIfListChecked(ctrl){")

            sb.Append("var chkBoxList = document.getElementById(document.getElementById(ctrl.id).controltovalidate);")

            sb.Append("var chkBoxCount= chkBoxList.getElementsByTagName(""input"");")

            sb.Append("for(var i=0;i<chkBoxCount.length;i++){")

            sb.Append("if(chkBoxCount.item(i).checked){")

            sb.Append("return true; }")

            sb.Append("}return false; ")

            sb.Append("}</script>")

            Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "JSScript", sb.ToString())

        End Sub

As you observe, we override the OnPreRender method and use the RegisterExpandoAttribute to assign the function name ‘CheckIfListChecked’ an attribute called ‘evaluationfunction’. The javascript function(CheckIfListChecked) takes one parameter, the validator object and returns ‘true’ if Valid (item in both Radiobuttonlist or CheckBoxList is checked) and ‘false’ if Invalid (Item in either Radiobuttonlist or CheckBoxList is not selected).

Note: If you observe, there is a call to the base.OnPreRender() in the OnPreRender method. This is done to make sure that if the users have turned off javascript on their browsers, then this call passes the control back to the page and allows the rendering to continue by calling base.OnPreRender() .

The javascript function is created using a StringBuilder object and is output using Page.ClientScript.RegisterClientScriptBlock()

When the page is run, the javascript output to the browser will look similar to the following:

<script type="text/javascript">

function CheckIfListChecked(ctrl)

{

var chkBoxList = document.getElementById(document.getElementById(ctrl.id).controltovalidate);

var chkBoxCount= chkBoxList.getElementsByTagName("input");

for(var i=0;i<chkBoxCount.length;i++)

{

if(chkBoxCount.item(i).checked)

{

return true;

}

}return false;

}

</script>

 

Step 7: The last step would be to add the EnableClientScript="true" to our custom validation controls as shown below:

        <CLV:ListValidator runat="server" ID="custLstVal" EnableClientScript="true" ControlToValidate="CheckBoxList1" ErrorMessage="At least one item in the checkboxlist should be checked" />

 

        <CLV:ListValidator runat="server" ID="custRadVal" EnableClientScript="true" ControlToValidate="RadioButtonList1" ErrorMessage="At least one item in the radiobuttonlist should be checked" />

 

That’s pretty much it. This time when you run the application, the custom validation control handles both server-side as well as client-side validation. If JavaScript is enabled on your browsers, the validation errors are displayed before the form is posted back to the server. The entire source code of the application can be downloaded from here. I hope you liked the article and I thank you for viewing it.