Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

UpdownNumeric, IP, Timer and Validated TextBox Controls using webcustomcontrols

0.00/5 (No votes)
9 Jul 2006 1  
Download EuroNetWebCustomControls suite Demoproject-26.3kb and the source code - 31 kb. This custom control suite contains UpdownNumerci, IP, Timer and Validated Text Box Controls. I created these controls using WebCustomContolsLibrary in .Net2003.

Sample Image - EuroNetWebControlDemoPage.jpg

Introduction

My current job involves migrating a part of our Windows application to Web application. We had  similar controls in our win app (IP control, Numeric Control and Timer control). The default web controls in Visual Studio do not provide the aforesaid functionality. That was when I decided to write a few controls on my own. There are 4 controls in all as described below:

Validated Textbox - This control exposes a  property NotAllowedChars. Specify the characters you DO NOT want the control to accept in this property. Please note that if you need to avoid the double quotation("), you should enter in the following format only - "  An additional property Width is also available to facilitate the developer to supply the width for the textbox.

UpdownNumeric - This control consists of a text box and two buttons. There are 2 proerties viz. Min and Max for setting the range of values to enter in the textbox. Values can be entered directly in the textbox. Alternately, the values can be incremented/decremented through the buttons provided. Just click on the button once to increment/decrement the value or hold the mouse on the button to increment/decrement automatically.

I have set default images for the buttons. If you want to put your image you can do so by setting the UpImage and DownImage properties.

Timer Control - I combined two different controls in this timer control. I have given a property named Type which is of Enum type. The default value is HourMin. In that time you can able see two textboxes and two buttons. The first textbox accepts only the Hour(24h Format). The second one accepts Minute.
If you change the Type property to HourMinSec, you can see the third textbox for Seconds. The button operation is same as above control. By default I have set the button images. If you want to change those images you will set it through the UpImage and DownImage properties.

IP Control - This control accepts IP address and consists of 4 textboxes separated by  hyphens (-).

Note:
Every control has the following properties

1. ClientSideScriptLocation. You should specify the location of the Javascript(Euronet.NetWebControlsValidation.js)  file here.
2. EuroNetCss. Specify the CSS Class Name.

Code Description for Validated Textbox

false),Category("Appearance"),DefaultValue("")>
public string Text
{
  get {return text; }
  set {text = value;}
}
false),Category("Appearance"),DefaultValue("")>
public string NotAllowedChar
{
  set {hNotAllowedChar = value;}
  get{return hNotAllowedChar;}
}

The Text property of my control is the same as the asp.net Textbox Control's Text Property. No further explanation is required.

The next property NotAllowedChar is my special property. Specify the characters you DO NOT want the control to accept in this property. I had a small problem - Characters within double quotes did not get validated. To overcome this problem I  made use of a hidden Textbox to maintain the NotAllowedCharacters. I pass the value of this hidden Textbox to the script. Characters within the double quot(��)  will be considered as validated string.

The only condition is if you enter the double quot ("), it should not work properly. But I have given the work around of this. See my following code.
protected override void Render(HtmlTextWriter output)
{
  output.WriteBeginTag("EuroControls");
  output.Write("\n<input type=hidden id="+ID+
               "_hidNotAllowedCharCode   Value=\""+NotAllowedChar+"\">");
  output.Write("\n<script language="'javascript'"   src='"+
               sScriptLocation+"'></script>");
  if(Enabled)
    output.Write("\n<input type=text name="+this.UniqueID+"  id="+
                 this.UniqueID+" onkeypress=keyRestrict(event,'"+
                 ID+"')  Value='"+Text+"' style='"+EuronetStyle+
                 "' class='"+CssClass+"' runat="server">");
  else
    output.Write("\n<input type=text readOnly name="+this.UniqueID+
                 " id="+this.UniqueID+" onkeypress=keyRestrict(event,'"+
                 ID+"') Value='"+Text+"' style='"+
                 EuronetStyle+"color:gray;' class='"+CssClass+
                 "' runat="server">");
}

You can set the Enabled and Disabled property also. In our page lifecycle scenario, the control�s value will not be persist when the controls are in disabled mode.

So I did not disable the control. Instead I set the read-only property of the control and changed the colors to make it look appear in disabled mode.
Note:This property is common for all the controls.

I inherited IPostBackDataHandler for persisting with the Postback data. See the below code.

public bool LoadPostData(String postDataKey, NameValueCollection values) 
{
  Text = values[this.UniqueID];
  return false;
}

Code Description for IP Control
The IP control consists of a total of 7 HtmlInputTextBox controls- four controls for user input and the rest act as separators.

In this control I inherited INamingContainer Interface to create unique id for every control.
The following code shows how the controls are created. I override the method CreateChildControls to create the controls.
protected override void CreateChildControls()
{
  ctlIpText1 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlIpText1.ID = "txtIP1";
  ctlIpText1.Attributes.Add("runat","Server");
  ctlIpText1.Attributes.Add("onkeypress","IsNumeric(event)");
  ctlIpText1.Attributes.Add("onfocus", "SelText('"+this.UniqueID+"_txtIP1')");
  ctlIpText1.Attributes.Add("tabIndex",(base.TabIndex+1).ToString());
  ctlIpText1.Attributes.Add("onblur", 
                            "ValidateIP('"+this.UniqueID+"','txtIP1')");
  ctlIpText1.MaxLength = 3;
  ctlIpText2 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlIpText2.ID = "txtIP2";
  ctlIpText2.Attributes.Add("runat","Server");
  ctlIpText2.Attributes.Add("onkeypress","IsNumeric(event)");
  ctlIpText2.Attributes.Add("onfocus", "SelText('"+this.UniqueID+"_txtIP2')");
  ctlIpText2.Attributes.Add("tabIndex",(base.TabIndex+2).ToString());
  ctlIpText2.Attributes.Add("onblur", ValidateIP('"+
                            this.UniqueID+"','txtIP2')");
  ctlIpText2.MaxLength = 3;
  ctlIpText3 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlIpText3.ID = "txtIP3";
  ctlIpText3.Attributes.Add("runat","Server");
  ctlIpText3.Attributes.Add("onkeypress","IsNumeric(event)");
  ctlIpText3.Attributes.Add("onfocus", "SelText('"+this.UniqueID+"_txtIP3')");
  ctlIpText3.Attributes.Add("tabIndex",(base.TabIndex+3).ToString());
  ctlIpText3.Attributes.Add("onblur", "ValidateIP('"+this.UniqueID+"','txtIP3')");
  ctlIpText3.MaxLength = 3;
  ctlIpText4 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlIpText4.ID = "txtIP4";
  ctlIpText4.Attributes.Add("runat","Server");
  ctlIpText4.Attributes.Add("onkeypress","IsNumeric(event)");
  ctlIpText4.Attributes.Add("onfocus", "SelText('"+this.UniqueID+"_txtIP4')");
  ctlIpText4.Attributes.Add("tabIndex", (base.TabIndex+4).ToString());
  ctlIpText4.Attributes.Add("onblur", "ValidateIP('"+
                            this.UniqueID+"','txtIP4')");
  ctlIpText4.MaxLength = 3;
  ctlIpText1.Value = SplitIp(Text, 0);
  ctlIpText2.Value = SplitIp(Text, 1);
  ctlIpText3.Value = SplitIp(Text, 2);
  ctlIpText4.Value = SplitIp(Text, 3);
  ctlHyText1 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlHyText1.ID = "txtHy1";
  ctlHyText1.Value = "-";
  ctlHyText1.Attributes.Add("tabIndex","5");
  ctlHyText1.Attributes.Add("readOnly","true");
  ctlHyText2 = new ystem.Web.UI.HtmlControls.HtmlInputText();
  ctlHyText2.ID = "txtHy2";
  ctlHyText2.Value = "-";
  ctlHyText2.Attributes.Add("tabIndex","6");
  ctlHyText2.Attributes.Add("readOnly","true");
  ctlHyText3 = new System.Web.UI.HtmlControls.HtmlInputText();
  ctlHyText3.ID = "txtHy3";
  ctlHyText3.Value = "-";
  ctlHyText3.Attributes.Add("tabIndex","7");
  ctlHyText3.Attributes.Add("readOnly","true");
  ctlTable = new System.Web.UI.HtmlControls.HtmlTable();
  ctlTable.Attributes.Add("style","BORDER-RIGHT: gray 0px solid; " + 
                          "BORDER-TOP: gray 0px solid; BORDER-LEFT: " + 
                          "gray 0px solid; BORDER-BOTTOM: gray 0px solid");
  ctlRow = new System.Web.UI.HtmlControls.HtmlTableRow();
  ctlRow.Attributes.Add("style", "BORDER-RIGHT: gray 0px solid; " + 
                        "BORDER-TOP: gray 0px solid; BORDER-LEFT: " + 
                        "gray 0px solid; BORDER-BOTTOM: gray 0px solid");
  ctlTable.Rows.Add(ctlRow);
  ctlCell = new System.Web.UI.HtmlControls.HtmlTableCell();
  ctlCell.Attributes.Add("style","BORDER-RIGHT: gray 0px solid; " + 
                         "BORDER-TOP: gray 0px solid; BORDER-LEFT: " + 
                         "gray 0px solid; BORDER-BOTTOM: gray 0px solid");
  ctlCell.Controls.Add(ctlIpText1);
  ctlCell.Controls.Add(ctlHyText1);
  ctlCell.Controls.Add(ctlIpText2);
  ctlCell.Controls.Add(ctlHyText2);
  ctlCell.Controls.Add(ctlIpText3);
  ctlCell.Controls.Add(ctlHyText3);
  ctlCell.Controls.Add(ctlIpText4);
  ctlRow.Cells.Add(ctlCell);
  this.Controls.Add(ctlTable);
}

The following property is used to get and set the IP address.
false), Category("Data"), DefaultValue("0"), 
    Description("The Text for Numeric TextBox")> 
public string Text 
{
  get
  {
    this.EnsureChildControls();
    return ctlIpText1.Value+"-"+ ctlIpText2.Value+"-"+
           ctlIpText3.Value+"-"+ctlIpText4.Value;
  }

  set
  {
    this.EnsureChildControls();
    string[] strarrIp = value.Split(new char[] {'-'});
    if(strarrIp != null)
    {
    ctlIpText1.Value = strarrIp[0];
    ctlIpText2.Value = strarrIp[1];
    ctlIpText3.Value = strarrIp[2];
    ctlIpText4.Value = strarrIp[3];
    }
    else
    {
    ctlIpText1.Value = "";
    ctlIpText2.Value = "";
    ctlIpText3.Value = "";
    ctlIpText4.Value = "";
    }
  }
}

EnsureChildControls method ensures that the current control has child controls. It then gets or sets a Text property for a child Textbox control in the current control's ControlCollection object.

Code Description for Timer Control

To form this control I used three HtmlInputTextbox and two HtmlButton controls. I give the option to developers to swap the control from HourMinSec Timer to HourMin and vice versa. In this control I used the same technique as in the above control.
But I have given additional features ie. Default images for updown buttons. So the developer can change this property to set images of his own.

I use a class for open the file dialog from property window. See the following code.

public class UrlImageEditor: System.Web.UI.Design.UrlEditor
{
  protected override string Caption
  {
    get
    {
    return "Select Image";
    }
  }
  protected override string Filter
  {
    get
    {
    return "ImageFiles(*.gif,*.jpg,*.jpeg,*.bmp,*.wmf," + 
           "*.png) |*.gif;*.jpg;*.jpeg;*.bmp;*.wmf;*.png|All Files(*.*)|*.*";
    }
  }
}
    
public class UrlFileEditor: System.Web.UI.Design.UrlEditor
{
  protected override string Caption
  {
    get
    {
    return "Select File";
    }
  }
  protected override string Filter
  {
    get
    {
    return "ScriptFile(*.js)|*.*";
    }
  }
}

I wrote the above classes in a separate class file (easy to understand).The following property shows how I used those classes.

[Category("Appearance"),Bindable(false),
  Description("Image to use if the down button is an image"),
  DefaultValue(""), Browsable(true),
  EditorAttribute(typeof(cEditor.UrlImageEditor), 
  typeof(System.Drawing.Design.UITypeEditor))]
public string ImageUp
{
  set
  {
    this.EnsureChildControls();
    ctlButtonUp.Src = value;
    sUpImagePath = value;
  }
  get
  {
    return sUpImagePath ;
  }
}

The EditorAttribute places a button in that property. This button launches the file dialog. I did the same thing for selecting the ClientSideScriptLocatin property.

There was a problem here too - when I swap the control from default I got some design issues and a script error. This was so since CreateChildControls method did not fire whenever you change the control type property.
So I explicitly clear all the controls and create the controls again when you change the control type. See the below property.

false), Category("Behavior"), 
   DefaultValue("ControlType.HourMinTimer"), 
   Description("Control Type")> 
public ControlType Type
{
  set
  {
    _Type = value;
    this.Controls.Clear();
    CreateChildControls();
    Text = "00:00:00";
    if(Directory.Exists(path+"/EuroNetWebControlsImages"))
    {
    ImageUp = path+"/EuroNetWebControlsImages/up.bmp";
    ImageDown = path+"/EuroNetWebControlsImages/down.bmp";
    }
    else
    {
        ImageUp = ImageUp;
    ImageDown = ImageDown;
    }
  }
  get
  {
    return _Type;
  }
}

The following code shows how default image is set to the buttons. While you drag and drop the control to your form, internally I create an Imagefolder to your application path and place the images in that folder. But before do this your application folder should have the write permission. Otherwise the default image will not get created.

private void LoadDefaultImage()
{
  try
  {
    path = GetAppFolder();
    if(!Directory.Exists(path+"/EuroNetWebControlsImages"))
    {
      Directory.CreateDirectory(path+"/EuroNetWebControlsImages");
    }
    System.IO.Stream sr;
    byte[] by;
    System.IO.MemoryStream ms;
    System.Drawing.Bitmap bm;
    if(!File.Exists(path+"/EuroNetWebControlsImages/up.ico"))
    {
    sr = System.Reflection.Assembly.LoadWithPartialName(
         "EuroNetWebControls").GetManifestResourceStream(
         "EuroNetWebControls.Images.up.bmp");
    by = new byte[sr.Length];
    sr.Read(by, 0, (int)sr.Length);
    ms = new System.IO.MemoryStream();
    ms.Write(by, 0, by.Length);
    bm = new Bitmap(ms);
    bm.Save(path+"/EuroNetWebControlsImages/up.bmp");
    ImageUp = path+"/EuroNetWebControlsImages/up.bmp";
    ms.Close();
     }
     else
     {
    ImageUp = path+"/EuroNetWebControlsImages/up.bmp";
     }

     if(!File.Exists(path+"/EuroNetWebControlsImages/down.ico"))
     {
    sr = System.Reflection.Assembly.LoadWithPartialName(
         "EuroNetWebControls").GetManifestResourceStream(
         "EuroNetWebControls.Images.down.bmp");
    by = new byte[sr.Length];
    sr.Read(by, 0, (int)sr.Length);
    ms = new System.IO.MemoryStream();
    ms.Write(by, 0, by.Length);
    bm = new Bitmap(ms);
    bm.Save(path+"/EuroNetWebControlsImages/down.bmp");
    ImageDown = path+"/EuroNetWebControlsImages/down.bmp";
    ms.Close();
     }
     else
     {
    ImageDown = path+"/EuroNetWebControlsImages/down.bmp";
     }
}
 catch{}
}

private string GetAppFolder()
{
  try
  {
    string path = Assembly.GetExecutingAssembly().CodeBase;
    path = path.Remove(0,8);
    path = path.Replace("/","\\");
    path = path.Substring(0,path.LastIndexOf("\\",path.Length,
                          path.Length - 1));
    return path.Substring(0,path.LastIndexOf("\\",path.Length,
                          path.Length - 1));
   }
   catch(Exception)
   {    return null;    }
}

Code Description for UpDownNumeric Control

This control contains the similar functionalities what I did in the Timer control.
In this control I added two properties Max and Min. The developer can set Maximum and Minimum values. Use this property the developer can restrict the range of values from user.
All the other things are same as Timer control.

false), Category("Misc"), DefaultValue("0"), 
    Description("To set the Minimum value of Numeric Textbox")> 
public string Min
{
  get
  {
    this.EnsureChildControls();
    return ctlHidMin.Value;
  }
  set
  {
    this.EnsureChildControls();
    ctlHidMin.Value = value;
    Text = value;
  }
}
false), Category("Misc"), DefaultValue("100"), 
    Description("To set the Maximum value of Numeric Textbox")> 
public string Max
{
  get
  {
    this.EnsureChildControls();
    return ctlHidMax.Value;
  }
  set
  {
    this.EnsureChildControls();
    ctlHidMax.Value = value;
  }
}

I have posted my JavaScript along with this article. That script is very easy to understand and does not need any explanation.

Points of Interest
I was trying to show the Style builder through the property window. As of now I can�t able to do. I searched everywhere. But I didn�t get. If you have any ideas to enhance the control and how to incorporate the Style Builder please post it.
It�s very helpful to me and other developers who are needed the same thing.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here