Saturday, January 19, 2013

Custom TextBox with built-in Validator(Asp .NET/C#)

In my previous two posts I demonstrated how to create a custom control based on the TextBox control, how to add new and override existing properties.  In this post I will create a custom TextBox control with a build in required validator.  There are many benefits to using this control over a standard TextBox and RequiredValidators controls among them is the ability to quickly change the requirement level of a field with minimal changes to the markup and consistent look of all required fields.

Step 1:  Create a class extending the TextBox control and add private RequiredFieldValidator variable.

public class TextBoxReqValidator : System.Web.UI.WebControls.TextBox
{
    #region Validator
    /// <summary>
    /// Validator
    /// </summary>
    private RequiredFieldValidator req;
    #endregion

Step 2:  Add properties you will want to set on the validator.

Notice that the Validation Group property overrides the textbox property and also sets the corresponding property on the validator if the validator is not null.  The Required property will be used to enable and disable the validator.  The rest of the properties will be used to set properties on the validator control.

#region Properties
/// <summary>
/// ValidationGroup Property
/// </summary>
public virtual string ValidationGroup
{
    get
    {
        string o = base.ValidationGroup;
        return o;
    }
    set
    {
        String oldValue = ValidationGroup;
        if (value != oldValue)
        {
            if (req != null)
            {
                req.ValidationGroup = value;
            }
            base.ValidationGroup = value;
        }
    }
}

/// <summary>
/// InvalidMessage Property
/// </summary>
[Browsable(true)]
[Description("InvalidMessage"), Category("Custom"), DefaultValue("")]
public virtual String InvalidMessage
{
    get
    {
        object o = ViewState["InvalidMessage"];
        if (o != null)
            return (String)o;
        return string.Empty; // Default value
    }
    set
    {
        String oldValue = InvalidMessage;
        if (value != oldValue)
        {
            if (req != null)
            {
                req.ErrorMessage = value;
            }
            ViewState["InvalidMessage"] = value;
        }
    }
}

/// <summary>
/// Required Property
/// </summary>
[Browsable(true)]
[Description("Required"), Category("Custom"), DefaultValue(false)]
public virtual bool Required
{
    get
    {
        object o = ViewState["Required"];
        if (o != null)
            return (bool)o;
        return false; // Default value
    }
    set
    {
        bool oldValue = Required;
        if (value != oldValue)
        {
            ViewState["Required"] = value;
        }
    }
}

/// <summary>
/// ClientScript Property
/// </summary>
[Browsable(true)]
[Description("ClientScript"), Category("Custom"), DefaultValue(true)]
public virtual bool ClientScript
{
    get
    {
        object o = ViewState["ClientScript"];
        if (o != null)
            return (bool)o;
        return true; // Default value
    }
    set
    {
        bool oldValue = ClientScript;
        if (value != oldValue)
        {
            if (req != null)
            {
                req.EnableClientScript = value;
            }
            ViewState["ClientScript"] = value;
        }
    }
}
#endregion

Step 3:  On Init

We will instantiate the RequiredFieldValidator in the OnInit event, we also set the validator properties.  You can see the full life cycle of the page and controls and the order of the events here.  Since we don't want our code to execute at design time we check if we're in design mode at the top of our method.

#region On Init
/// <summary>
/// Init
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
    //if we want this control to render at design time we need this code.
    if (this.DesignMode)
    {
        base.OnInit(e);
        return;
    }
    //instantiate and setup the validator
    req = new RequiredFieldValidator();
    req.Enabled = false;
    req.ControlToValidate = this.ID;
    req.ErrorMessage = this.InvalidMessage;
    req.Text = "Required";
    req.EnableClientScript = ClientScript;
    req.ValidationGroup = this.ValidationGroup;
    req.Display = ValidatorDisplay.Dynamic;
    Controls.Add(req);
}
#endregion

Step 4: Render

If the field is required we will render the textbox  and the validator controls.
#region Render
/// <summary>
/// Render 
/// </summary>
/// <param name="writer">Writer</param>
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    //if we want this control to render at design time we need this code.        
    if (this.DesignMode)
    {
        base.Render(writer);
        return;
    }
    //if required property is set to true enable the validator
    if (Required == true)
    {
        base.Render(writer);
        writer.Write("<span style=\"color:red;\">*</span>");
        req.Enabled = true;
        req.RenderControl(writer);
    }
    else
    {
        base.Render(writer);
    }
}
#endregion

Usage Example:

Markup
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CustomControls._Default" %>
<%@ Register assembly="CustomControls" namespace="CustomControls.Controls" tagprefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <cc1:TextBoxReqValidator ID="TextBoxReqValidator1" runat="server" Required="true"></cc1:TextBoxReqValidator>
        <br />
        <asp:CheckBox ID="TextBoxReqCheckBox" runat="server" Checked="true" Text="Required"
            AutoPostBack="true" oncheckedchanged="TextBoxReqCheckBox_CheckedChanged" />
        <asp:Button ID="Submit" runat="server" CausesValidation="true" Text="Submit" />
    </div>
    </form>
</body>
</html>

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CustomControls
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void TextBoxReqCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            TextBoxReqValidator1.Required = TextBoxReqCheckBox.Checked;
        }
    }
}

Examples:

Required Field:
 
Required Field after validation:
 

Complete Source:

 CustomControls_RequiredTextBox.zip

Demo:

Demo 



Friday, January 11, 2013

Custom Controls - Overriding Properties(Asp .NET/C#)

In my previous post I walked thru the process of extending a TextBox control by adding new properties.  In this post I will show how to override an existing property.  This can be useful when additional logic is required when a value of your property changes.  One example would be adding code to cleanse the data to prevent SQL injection attacks.

This post picks up where the previous post left off, I will override the text property of the CustomTextBox control I created previously.

Open the extended control created in the previous post and add the following code.


/// <summary>
/// Text Property
/// </summary>
public virtual string Text
{
    get
    {
        string o = base.Text;
        //perform any additonal logic here
        return o;
    }
    set
    {
        string o = value;
        //perform any additonal logic here
        base.Text = o; 
    }
}

Complete Source: 

CustomControls_TextProperty.zip