Monday, June 17, 2013

Custom Google Maps Control (Asp .NET/C#)

In this post I will create a custom Asp .NET Google Maps control.  This will allow you to quickly add maps to your applications by just dropping the control on the page.

Step 1:  Add jQuery and gmap3 JavaScript and CSS files to your project.

The jQuery files can be found here and the gmap3 files can be found here.  Or you can just download the sample project using the link at the end of this post.

Step 2:  Adding References to the .js and .css files.

You can add the references to each page you plan to use your controls on, or if you are using mater pages you can add the references there.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>One More IT Blog</title>
    <script src="Scripts/jquery-2.0.0.js"></script> 
    <script src="Scripts/gmap3.js"></script>
    <script src="http://maps.googleapis.com/maps/api/js?sensor=false" type="text/javascript"></script>

Step 3:  Create a class extending a WebConrol.


[Toolbox("<{0}:MapsControl runat=\"server\">")] 
public class MapsControl : WebControl
{

Step 4: Add Width and Height Property with default values


#region Size
/// <summary>
/// Width
/// </summary>
public int Width
{
    get
    {
        object s = (object)ViewState["Width"];
        return ((s == null) ? 500 : (int)s);
    }
    set
    {
        ViewState["Width"] = value;
    }
}

/// <summary>
/// Height
/// </summary>
public int Height
{
    get
    {
        object s = (object)ViewState["Height"];
        return ((s == null) ? 500 : (int)s);
    }
    set
    {
        ViewState["Height"] = value;
    }
}
#endregion

Step 5: Add address Properties.


#region Address
/// <summary>
/// Label
/// </summary>
[Bindable(true)]
[Category("Address")]
[DefaultValue("")]
[Localizable(true)]
public string Name
{
    get
    {
        String s = (String)ViewState["Name"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["Name"] = value;
    }
}

/// <summary>
/// Address
/// </summary>
[Bindable(true)]
[Category("Address")]
[DefaultValue("")]
[Localizable(true)]
public string AddressLine1
{
    get
    {
        String s = (String)ViewState["AddressLine1"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["AddressLine1"] = value;
    }
}

/// <summary>
/// City
/// </summary>
[Bindable(true)]
[Category("Address")]
[DefaultValue("")]
[Localizable(true)]
public string City
{
    get
    {
        String s = (String)ViewState["City"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["City"] = value;
    }
}

/// <summary>
/// State
/// </summary>
[Bindable(true)]
[Category("Address")]
[DefaultValue("")]
[Localizable(true)]
public string State
{
    get
    {
        String s = (String)ViewState["State"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["State"] = value;
    }
}

/// <summary>
/// Zip Code
/// </summary>
[Bindable(true)]
[Category("Address")]
[DefaultValue("")]
[Localizable(true)]
public string ZipCode
{
    get
    {
        String s = (String)ViewState["ZipCode"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["ZipCode"] = value;
    }
}
#endregion

Step 6: Add helper methods.


#region Helper
/// <summary>
/// Generate the Bubble text
/// </summary>
/// <returns></returns>
private string BubbleText()
{
    return Name + "<br/>" + 
        AddressLine1 + "<br/>" +
        City + ", " + 
        State + " " + 
        ZipCode + "<br/>" + 
        "<a href='http://maps.google.com/maps?daddr=" + GetAddress().Replace(' ', '+') + "' target=_new>Directions</a>";
}

/// <summary>
/// Crate an address string for google maps
/// </summary>
/// <returns></returns>
private string GetAddress()
{
    return AddressLine1+", "+City+", "+State+" "+ZipCode;
}

/// <summary>
/// Create a unique id for the div
/// </summary>
private string CtrlId
{
    get
    {
        return this.ClientID + "Map";
    }
}
#endregion

Step 7: Add a method that will generate the needed JavaScript.


#region Scripts
/// <summary>
/// Generates Javascript and CSS
/// </summary>
/// <returns></returns>
private string Scripts()
{
    string script ="<style>\r\n"+
    "      body{\r\n"+
    "        text-align:center;\r\n"+
    "      }\r\n"+
    "      #"+CtrlId+".gmap3{\r\n"+
    "        margin: 20px auto;\r\n"+
    "        border: 1px dashed #C0C0C0;\r\n"+
    "        width: " + Width + "px;\r\n" +
    "        height: " + Height + "px;\r\n" +
    "      }\r\n"+
    "    </style>\r\n"+
    "    \r\n"+
    "    <script type=\"text/javascript\">\r\n"+
    "       \r\n"+
    "     $(function(){\r\n"+
    "        $('#"+CtrlId+"').gmap3(\r\n"+ 
    "{ \r\n"+ 
    "          marker:{\r\n"+
    "            address: \"" + GetAddress() + "\", data:\"\", options:{icon: \"http://maps.google.com/mapfiles/marker_green.png\"}}\r\n" +
    "          ,\r\n"+
    "  infowindow:{\r\n" +
    "            address:\"" + GetAddress() + "\",\r\n" +
    "     options:{\r\n" +
    "       content: \"" + BubbleText() + "\"\r\n" +
    "     },\r\n" +
    "     events:{\r\n" +
    "       closeclick: function(infowindow){\r\n" +
    "       }\r\n" +
    "     }\r\n" +
    "},\r\n" +
    "          map:{\r\n"+ 
    "            options:{\r\n"+ 
    "              zoom: 14\r\n"+ 
    "            }\r\n"+ 
    "          }\r\n"+ 


    "        });\r\n"+ 
    "});\r\n"+
    "    </script>\r\n";
    return script;
}
#endregion

Step 8: Override the RenderContents method.

Notice that the "id" property of the div is being set to a unique value for each instance of the control.  This will allow you to drop multiple map controls onto a page.

#region Render
/// <summary>
/// Render Control
/// </summary>
/// <param name="output"></param>
protected override void RenderContents(HtmlTextWriter output) {
    string html = "<div id=\"" + CtrlId + "\" class=\"gmap3\"></div>";
    output.Write(Scripts() + html);
}
#endregion

Usage Example:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="MapsDemo.aspx.cs" Inherits="CustomControls.MapsDemo" %>
<%@ Register assembly="CustomControls" namespace="CustomControls.Controls" tagprefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">    
    <cc1:MapsControl ID="MapsControl1" runat="server" 
        Name="Willis Tower" 
        AddressLine1="233 South Wacker Drive" 
        City="Chicago" 
        State="IL" 
        ZipCode="60606"></cc1:MapsControl>
    <cc1:MapsControl ID="MapsControl2" runat="server" 
        Name="Omni Hotel"
        AddressLine1="675 L Street" 
        Height="350" 
        Width="350" 
        City="San Diego" 
        State="CA" 
        ZipCode="92101"></cc1:MapsControl>
</asp:Content>


Code behind
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 MapsDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}






Complete Source:

 CustomControls_Maps.zip

Demo:

Demo 1


Friday, May 17, 2013

jQuery Enhanced Custom ListBox Control(Asp .NET/C#)

In my last post I created a jQuery enhanced drop down control.  In this post I will use jQuery to enhance a list box control.  If you saw the previous post just look at steps 3, 4 and 5.

Step 1:  Add jQuery and jQuery UI Javascript and CSS files to your project.

The jQuery files can be found here and the jQuery UI files can be found here, and Chosen plugin file can be found here.  Or you can just download the sample project using the link at the end of this post.

Step 2:  Adding References to the .js and .css files.

You can add the references to each page you plan to use your controls on, or if you are using mater pages you can add the references there.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>One More IT Blog</title>
    <link rel="stylesheet" href="css/smoothness/jquery-ui-1.10.1.custom.css" /> 
    <link rel="stylesheet" href="Scripts/chosen/chosen.css" />  
    <script src="Scripts/jquery-1.9.1.js"></script>
    <script src="Scripts/jquery-ui-1.10.1.custom.js"></script>
    <script src="Scripts/chosen/chosen.jquery.js"></script>

Step 3:  Create a class extending the ListBox or the ListBoxReq control created in one of the previous posts.

public class ListBoxJQ : ListBoxReq
{

Step 4: OnPreRender

We will register our script in the OnPreRender method.

#region Pre Render
/// <summary>
/// PreRender
/// </summary>
/// <param name="e"></param>
protected override void OnPreRender(EventArgs e)
{
     base.OnPreRender(e);
     // Check to see if the client script is already registered.
     if (!this.Page.ClientScript.IsStartupScriptRegistered(String.Format("jQuery_{0}", this.ClientID)))
     {
         String script = "$(document).ready(function(){$('#" +
            this.ClientID + "').chosen(); });";
         script = "<script type=\"text/javascript\">" + script + "</script>";
           this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), String.Format("jQuery_{0}", this.ClientID), script, false);
     }
}
#endregion

Step 5: AddAttributesToRender

Now we will need to enable the multi-select functionality.

#region Multi Select Setup
/// <summary>
/// We need to enable the multi select behavior of the control.
/// </summary>
/// <param name="writer"></param>
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
    // Show the ListItem text as Bold 
    writer.AddAttribute("multiple", "");

    // Call the Base's AddAttributesToRender method.
    base.AddAttributesToRender(writer);
}
#endregion

Usage Example:

In the example below notice the FromControl and ThruControl properties.
Markup
<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="JQueryEnhancedControlsDemo.aspx.cs" Inherits="CustomControls.JQueryEnhancedControlsDemo" %>
<%@ Register assembly="CustomControls" namespace="CustomControls.Controls" tagprefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <cc1:ListBoxJQ ID="ListBoxJQ" runat="server" Width="350px" Required="true">
        <asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
        <asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
        <asp:ListItem Text="Option 3" Value="3"></asp:ListItem>
        <asp:ListItem Text="Option 4" Value="4"></asp:ListItem>
    </cc1:ListBoxJQ>
    <br />
    <asp:CheckBox ID="ListBoxJQCheckBox" runat="server" Checked="true" Text="Required"
        AutoPostBack="true" OnCheckedChanged="ListBoxJQReqCheckBox_CheckedChanged" />
    <br />
    <asp:Button ID="Submit" runat="server" CausesValidation="true" Text="Submit" />
</asp:Content>

Code behind
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 JQueryEnhancedControlsDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void ListBoxJQReqCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ListBoxJQ.Required = ListBoxJQCheckBox.Checked;
        }
    }
}








Complete Source:

 CustomControls_ListBox.zip

Demo:

Demo 1

Demo 2 


Saturday, April 6, 2013

jQuery Enhanced Custom Date Range Control(Asp .NET/C#)

In my last post I created a jQuery enhanced date picker control.  In this post I will further enhance the control by making it a date range control.  If you saw the previous post just look at steps 4 and 5.

Step 1:  Add jQuery and jQuery UI Javascript and CSS files to your project.

The jQuery files can be found here and the jQuery UI files can be found here,  Or you can just download the sample project using the link at the end of this post.

Step 2:  Adding References to the .js and .css files.

You can add the references to each page you plan to use your controls on, or if you are using mater pages you can add the references there.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>One More IT Blog</title>
    <link rel="stylesheet" href="css/smoothness/jquery-ui-1.10.1.custom.css" /> 
    <link rel="stylesheet" href="Scripts/chosen/chosen.css" />  
    <script src="Scripts/jquery-1.9.1.js"></script>
    <script src="Scripts/jquery-ui-1.10.1.custom.js"></script>
    <script src="Scripts/chosen/chosen.jquery.js"></script>

Step 3:  Create a class extending the TextBox or the TextBoxReqValidator control created in one of the previous posts.

public class TextBoxReqValidator : TextBoxReqValidator
{

Step 4: Add Additional Properties.

We will use these properties to specify the name of the start and end of range user controls.
        #region Properties
        /// <summary>
        /// Name of the From Control
        /// </summary>
        [Browsable(true)]
        [Description("From Date Control"), Category("Custom"), DefaultValue("")]
        public virtual String FromControl
        {
            get
            {
                object o = ViewState["FromProp"];
                if (o != null)
                    return (String)o;
                return "";
            }
            set
            {
                String oldValue = FromControl;
                if (value != oldValue)
                {
                    ViewState["FromProp"] = value;
                }
            }
        }

        /// <summary>
        /// Name of the Thru Control
        /// </summary>
        [Browsable(true)]
        [Description("Thru Date Control"), Category("Custom"), DefaultValue("")]
        public virtual String ThruControl
        {
            get
            {
                object o = ViewState["ThruProp"];
                if (o != null)
                    return (String)o;
                return "";
            }
            set
            {
                String oldValue = ThruControl;
                if (value != oldValue)
                {
                    ViewState["ThruProp"] = value;
                }
            }
        }
        #endregion 
 

Step 5: OnPreRender

We will register our script in the OnPreRender method.  We will only register our script if the control is enabled.  First we will check if the FromControl property is set, if it is we know that our control specifies the end of the date range.  If the FromControl property was not set we will check the ThruControl property, if it is set we know that our control specifies the beginning of the date range.  If both properties are not set we will treat our control as a standard date picker.
        #region Pre Render
        /// <summary>
        /// PreRender
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (Enabled == true)
            {
                // Check to see if the client script is already registered.
                if (!this.Page.ClientScript.IsStartupScriptRegistered(String.Format("jQuery_{0}", this.ClientID)))
                {
                    String script = string.Empty;
                    if (FromControl != string.Empty)
                    {
                        script = "$(document).ready(function(){$('#" +
                             this.ClientID + "').datepicker(" +
                             " {defaultDate: \"+1w\", changeMonth: true," +
                             "  numberOfMonths: 3,onClose: function( selectedDate ) {" +
                             " $( '#" + FindControl(FromControl).ClientID + "' ).datepicker( \"option\", \"maxDate\", selectedDate );" +
                             "}}); });";
                    }
                    else if (ThruControl != string.Empty)
                    {
                        script = "$(document).ready(function(){$('#" +
                             this.ClientID + "').datepicker(" +
                             " {defaultDate: \"+1w\", changeMonth: true,"+
                             "  numberOfMonths: 3,onClose: function( selectedDate ) {"+
                             " $( '#"+ FindControl(ThruControl).ClientID+"' ).datepicker( \"option\", \"minDate\", selectedDate );"+ 
                             "}}); });";
                    }
                    else
                    {

                         script = "$(document).ready(function(){$('#" +
                            this.ClientID + "').datepicker(); });";
                    }
                    script = "<script type=\"text/javascript\">" + script + "</script>";
                    this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), String.Format("jQuery_{0}", this.ClientID), script, false);
                }
            }
        }
        #endregion

Usage Example:

In the example below notice the FromControl and ThruControl properties.
Markup
<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="DateControlsDemo.aspx.cs" Inherits="CustomControls.DateControlsDemo" %>
<%@ Register Assembly="CustomControls" Namespace="CustomControls.Controls" TagPrefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <cc1:DateRangePickerJQ runat="server" ID="FromControl" ThruControl="ThruControl"></cc1:DateRangePickerJQ>
    <cc1:DateRangePickerJQ runat="server" ID="ThruControl" FromControl="FromControl"></cc1:DateRangePickerJQ>
    <br />
    <asp:Button ID="Submit" runat="server" CausesValidation="true" Text="Submit" />
</asp:Content>

Complete Source:

 CustomControls_DateTextBox.zip

Demo:

Demo 1

Demo 2 


Monday, March 25, 2013

jQuery Enhanced Custom Date Control(Asp .NET/C#)

Adding jQuery to ASP.NET controls allows you to further enhance your custom controls.  One way to do this is by adding java script to pages and initializing your controls after the page is done loading.  Another way is to add the java script to the control in the PreRender method.

Step 1:  Add jQuery and jQuery UI Javascript and CSS files to your project.

The jQuery files can be found here and the jQuery UI files can be found here,  Or you can just download the sample project using the link at the end of this post.

Step 2:  Adding References to the .js and .css files.

You can add the references to each page you plan to use your controls on, or if you are using mater pages you can add the references there.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>One More IT Blog</title>
    <link rel="stylesheet" href="css/smoothness/jquery-ui-1.10.1.custom.css" /> 
    <link rel="stylesheet" href="Scripts/chosen/chosen.css" />  
    <script src="Scripts/jquery-1.9.1.js"></script>
    <script src="Scripts/jquery-ui-1.10.1.custom.js"></script>
    <script src="Scripts/chosen/chosen.jquery.js"></script>

Step 3:  Create a class extending the TextBox or the TextBoxReqValidator control created in one of the previous posts.

public class TextBoxReqValidator : TextBoxReqValidator
{

Step 4: OnPreRender

We will register our script in the OnPreRender method.  The script attaches the data picker functionality to our text box control.
        #region Pre Render
        /// <summary>
        /// PreRender
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (Enabled == true)
            {
                // Check to see if the client script is already registered.
                if (!this.Page.ClientScript.IsStartupScriptRegistered(String.Format("jQuery_{0}", this.ClientID)))
                {
                    String script = "$(document).ready(function(){$('#" +
                        this.ClientID + "').datepicker(); });";
                    script = "<script type=\"text/javascript\">" + script + "</script>";
                    this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), String.Format("jQuery_{0}", this.ClientID), script, false);
                }
            }
        }
        #endregion

Usage Example:

Markup
<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="DateControlsDemo.aspx.cs" Inherits="CustomControls.DateControlsDemo" %>
<%@ Register Assembly="CustomControls" Namespace="CustomControls.Controls" TagPrefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <cc1:DatePickerJQ runat="server" Id="DatePickerJQ"></cc1:DatePickerJQ>
    <br />
    <asp:Button ID="Submit" runat="server" CausesValidation="true" Text="Submit" />
</asp:Content>

Example:


Complete Source:

 CustomControls_DateTextBox.zip

Demo:

Demo 1

Demo 2 



Monday, March 4, 2013

Custom Multi Select ListBox with built-in Validator(Asp .NET/C#)

In my previous posts I walked thru the steps of adding a required validator and custom properties to a control.  In this post I will show how to do the same to a list box control.

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

    public class ListBoxReq : ListBox
    {
        #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. This code is almost the same as the previous example except we force the SelectionMode property to allow multiple selections.

#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;
    }
    //default to multi select
    this.SelectionMode = ListSelectionMode.Multiple;
    //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>
public override void RenderControl(HtmlTextWriter writer)
{
    //if we want this control to render at design time we need this code.        
    if (this.DesignMode)
    {
        base.RenderControl(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.RenderControl(writer);
    }
}
#endregion

Usage Example:

Markup
<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="ListBoxDemo.aspx.cs" Inherits="CustomControls.ListBoxDemo" %>
<%@ Register Assembly="CustomControls" Namespace="CustomControls.Controls" TagPrefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <cc1:ListBoxReq ID="ListBox" runat="server" Width="350px" Required="true">
        <asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
        <asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
        <asp:ListItem Text="Option 3" Value="3"></asp:ListItem>
        <asp:ListItem Text="Option 4" Value="4"></asp:ListItem>
    </cc1:ListBoxReq>
    <br />
    <asp:CheckBox ID="ListBoxReqCheckBox" runat="server" Checked="true" Text="Required"
        AutoPostBack="true" OnCheckedChanged="ListBoxReqCheckBox_CheckedChanged" />
        <asp:button id="Submit" runat="server" causesvalidation="true" text="Submit" />
</asp:Content>

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 ListBoxDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void ListBoxReqCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ListBox.Required = ListBoxReqCheckBox.Checked;
        }
    }
}

Examples:

Required Field:

Required Field after validation:



Complete Source:

 CustomControls_ListBox.zip

Demo:

Demo 1

Demo 2 

Friday, February 15, 2013

Custom DropDown/DropDownList/ComboBox with built-in Validator(Asp .NET/C#)

In my last post I described how to create a custom text box control with a built in required validator.  In this post I will describe how to do the same to a drop down list control.  When I first started to work on this example I ran into an issue where I couldn't add the validator control to the control collection.  My next approach involved creating a composite control, this approach is a lot more flexible but also requires significantly more work.  Fortunately I came across this article which provided me with a simple solution to my original problem.  The steps below are almost identical to the ones found in my previous post.  There is also a link to a working demo of the control at the end of the post.

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

public class DropDownReqValidator : DropDownList 
{
    #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>
public override void RenderControl(HtmlTextWriter writer)
{
    //if we want this control to render at design time we need this code.        
    if (this.DesignMode)
    {
        base.RenderControl(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.RenderControl(writer);
    }
}
#endregion

Step 5: Override the CreateCustomControl method.

In order to add the validator control to the drop down list we need to override the Create Custom Control method.
#region Create Control Collection
/// <summary>
/// Override of the Create Control Collection Method
/// based on http://www.codeproject.com/Articles/20055/Does-Not-Allow-Child-Controls-Error 
/// </summary>
/// <returns></returns>
protected override System.Web.UI.ControlCollection CreateControlCollection()
{
    return new ControlCollection(this);
}
#endregion

Usage Example:

Markup
<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="DropDownReq.aspx.cs" Inherits="CustomControls.DropDownReq" %>
<%@ Register assembly="CustomControls" namespace="CustomControls.Controls" tagprefix="cc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <cc1:DropDownReqValidator ID="DropDownReqValidator1" runat="server" Required="true">
        <asp:ListItem Text="" Value=""></asp:ListItem>
        <asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
        <asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
    </cc1:DropDownReqValidator>
    <br />
    <asp:checkbox id="DropDownReqCheckBox" runat="server" checked="true" text="Required"
        autopostback="true" oncheckedchanged="DropDownReqCheckBox_CheckedChanged" />
    <asp:button id="Submit" runat="server" causesvalidation="true" text="Submit" />
</asp:Content>

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 DropDownReq : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void DropDownReqCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            DropDownReqValidator1.Required = DropDownReqCheckBox.Checked;
        }
    }
}

Examples:

Required Field:

Required Field after validation:



Complete Source:

 CustomControls_DropDown.zip

Demo:

Demo 1

Demo 2 

Tuesday, February 5, 2013

Compare Excel Spreadsheets

Below is a VBA script that will compare 2 spreadsheets, highlight the differences and add a note to each cell to show the value on the other sheet.  Additionally all the differences are noted on the third sheet.  The sample sheet can be found here.












Sub CompareWorkSheets()
    Dim c1 As Range
    Dim c2 As Range
    Dim RowPos As Long
     
    Sheet3.Range("A1") = "Row"
    Sheet3.Range("B1") = "Column"
    Sheet3.Range("C1") = "Sheet1"
    Sheet3.Range("D1") = "Sheet2"
     
    RowPos = 1
     
    For Each c1 In Sheet1.UsedRange       
        If c1.Text <> Sheet2.Cells(c1.Row, c1.Column).Text Then
            Sheet1.Cells(c1.Row, c1.Column).Interior.Color = RGB(255, 251, 204)
            Sheet1.Cells(c1.Row, c1.Column).ClearComments
            Sheet1.Cells(c1.Row, c1.Column).AddComment Sheet2.Cells(c1.Row, c1.Column).Text
             
            Sheet2.Cells(c1.Row, c1.Column).Interior.Color = RGB(255, 251, 204)
            Sheet2.Cells(c1.Row, c1.Column).ClearComments
            Sheet2.Cells(c1.Row, c1.Column).AddComment c1.Text
             
            RowPos = RowPos + 1
            Sheet3.Cells(RowPos, 1) = c1.Row
            Sheet3.Cells(RowPos, 2) = c1.Column
            Sheet3.Cells(RowPos, 3) = c1
            Sheet3.Cells(RowPos, 4) = Sheet2.Cells(c1.Row, c1.Column)
        End If
    Next c1
End Sub

Alternative version of the code leaves the first 2 sheets unchanged and shows all of the differences on the third sheet.

Sub CompareWorkSheets()
    Dim c1 As Range
    Dim c2 As Range
    Dim RowPos As Long
     
    Sheet3.Range("A1") = "Row"
    Sheet3.Range("B1") = "Column"
    Sheet3.Range("C1") = "Sheet1"
    Sheet3.Range("D1") = "Sheet2"
     
    RowPos = 1
     
    For Each c1 In Sheet1.UsedRange
        If c1.Text <> Sheet2.Cells(c1.Row, c1.Column).Text Then
            Sheet3.Cells(c1.Row, c1.Column).Interior.Color = RGB(255, 251, 204)
            Sheet3.Cells(c1.Row, c1.Column).ClearComments
            Sheet3.Cells(c1.Row, c1.Column).AddComment Sheet2.Cells(c1.Row, c1.Column).Text
            Sheet3.Cells(c1.Row, c1.Column) = c1
            
        Else
            Sheet3.Cells(c1.Row, c1.Column).Interior.Color = RGB(255, 255, 255)
            Sheet3.Cells(c1.Row, c1.Column).ClearComments
            Sheet3.Cells(c1.Row, c1.Column) = c1
        End If
    Next c1
End Sub

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