Some time ago I needed a control that would allow me to type a time value in 24-hour format and obtain its equivalent in minutes. It was nothing fancy, just a text box with a validator to ensure the proper formatting. It turned out later that I had to create a kind of spreadsheet with plenty of such controls on a page. Instead of replicating the same code, I turned it into an ASP.NET custom control.

At first, I created a class library project in Visual Studio and added an ASP.NET custom control template. Next, I added the following code for my custom control. I named my control TimeTextBox. It is a simple composite control that contains two elements: a text box to enter a time value and a regular expression validator:

using System;
using System.Globalization;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WBS.CustomControls
{
    [ValidationPropertyAttribute("Minutes")]
    [ToolboxData("<{0}:TimeTextBox  Width='100' runat=server>")]
    public class TimeTextBox : WebControl, INamingContainer
    {
        // Component controls.
        private TextBox txtTime;
        private RegularExpressionValidator valRegTime;

        /// 
        /// Returns the number of minutes calculated from the entered time value.
        /// The time value must be provided in the 24-hour format. Otherwise, it 
        /// is considered invalid and the Minutes property returns -1.
        /// 
        public int Minutes
        {
            get
            {
                string[] formats = { "H:mm", "HH:mm" };
                DateTime time;

                EnsureChildControls();

                if (DateTime.TryParseExact(txtTime.Text, formats, null, DateTimeStyles.AllowWhiteSpaces, out time))
                    return time.Hour * 60 + time.Minute;
                else
                    return -1;
            }
        }

        public override Unit Width
        {
            set
            {
                EnsureChildControls();
                txtTime.Width = value;
            }
            get
            {
                EnsureChildControls();
                return txtTime.Width;
            }
        }

        public string ErrorMessage
        {
            set
            {
                EnsureChildControls();
                valRegTime.ErrorMessage = value;
            }
            get
            {
                EnsureChildControls();
                return valRegTime.ErrorMessage;
            }
        }

        protected override void CreateChildControls()
        {
            this.Controls.Clear();

            txtTime = new TextBox();
            txtTime.ID = "txtTime";
            txtTime.Width = Unit.Percentage(100);
            txtTime.MaxLength = 6;

            valRegTime = new RegularExpressionValidator();
            valRegTime.ID = "valRegTime";
            valRegTime.Enabled = true;
            valRegTime.ControlToValidate = txtTime.ID;
            valRegTime.Text = "";
            valRegTime.Display = ValidatorDisplay.Dynamic;
            valRegTime.EnableClientScript = true;
            valRegTime.ErrorMessage = "Invalid";
            valRegTime.ForeColor = System.Drawing.Color.Red;
            valRegTime.ValidationExpression = "^(([0-9])|([0-1][0-9])|([2][0-3])):(([0-5][0-9]))$";

            this.Controls.Add(txtTime);
            this.Controls.Add(valRegTime);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            txtTime.RenderControl(writer);
            valRegTime.RenderControl(writer);
        }
    }
}

Next, I created a test page to see my control in action:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebTest.Default" %>
<%@ Register TagPrefix="wbs" Namespace="WBS.CustomControls" Assembly="WBS.CustomControls" %>

<html>
<head runat="server">
    <title>Test</title>
    <style>
        * { font-family: Arial; font-size: 10pt; }
    </style>
</head>
<body>
    <form id="form1" runat="server">

        <wbs:TimeTextBox id="TimeTextBoxFrom" width="100" runat="server" />
        <wbs:TimeTextBox id="TimeTextBoxTo" width="100" runat="server" />

        <br /><br />

        <asp:Button ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click" runat="server" />

    </form>
</body>
</html>
using System;
using System.Diagnostics;

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

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            Debug.WriteLine(String.Format("Time from: {0} min", TimeTextBoxFrom.Minutes.ToString()));
            Debug.WriteLine(String.Format("Time to: {0} min", TimeTextBoxTo.Minutes.ToString()));
        }
    }
}

The above code creates two TimeTextBoxes. You can press the Submit button to see values returned from the TimeTextBoxs in the Visual Studio's Output window.

You can download the entire code from here