65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 WebCustomControls 的 UpdownNumeric、IP、Timer 和 Validated TextBox 控件

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (1投票)

2006年7月10日

5分钟阅读

viewsIcon

33987

downloadIcon

647

下载 EuroNetWebCustomControls 套件演示项目 - 26.3kb 和源代码 - 31 kb。此自定义控件套件包含 UpdownNumerci、IP、Timer 和 Validated Text Box 控件。我使用 .Net2003 中的 WebCustomContolsLibrary 创建了这些控件。

Sample Image - EuroNetWebControlDemoPage.jpg

引言

我目前的工作涉及将我们部分 Windows 应用程序迁移到 Web 应用程序。我们的 Win 应用中有类似的控件(IP 控件、Numeric 控件和 Timer 控件)。Visual Studio 中的默认 Web 控件不提供上述功能。那时我决定自己编写一些控件。总共有 4 个控件,如下所述:

Validated Textbox - 此控件公开一个名为 NotAllowedChars 的属性。在此属性中指定您不希望控件接受的字符。请注意,如果您需要避免使用双引号("),则应仅按以下格式输入 - "。还有一个 Width 属性,方便开发人员为文本框提供宽度。

UpdownNumeric - 此控件包含一个文本框和两个按钮。有 2 个属性:MinMax,用于设置文本框中输入值的范围。值可直接在文本框中输入。或者,可以通过提供的按钮来增加/减少值。只需单击按钮一次即可增加/减少值,或者将鼠标按住按钮即可自动增加/减少。

我已为按钮设置了默认图像。如果您想使用自己的图像,可以通过设置 UpImageDownImage 属性来实现。

Timer Control - 我在这个计时器控件中组合了两个不同的控件。我提供了一个名为 Type 的属性,它是 Enum 类型。默认值为 HourMin。在这种情况下,您可以看到两个文本框和两个按钮。第一个文本框只接受小时(24 小时制)。第二个文本框接受分钟。
如果将 Type 属性更改为 HourMinSec,您将看到用于秒的第三个文本框。按钮操作与上述控件相同。默认情况下,我已设置按钮图像。如果您想更改这些图像,可以通过 UpImageDownImage 属性进行设置。

IP Control - 此控件接受 IP 地址,包含 4 个由连字符 (-) 分隔的文本框。

注意
每个控件都具有以下属性:

1. ClientSideScriptLocation。您应该在此处指定 Javascript (Euronet.NetWebControlsValidation.js) 文件的位置。
2. EuroNetCss。指定 CSS 类名。

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;}
}

我的控件的 Text 属性 与 asp.net Textbox 控件的 Text 属性相同。无需进一步解释。

下一个 NotAllowedChar 属性 是我的特殊属性。在此属性中指定您不希望控件接受的字符。我遇到一个小问题 - 双引号内的字符未得到验证。为了解决这个问题,我使用了一个隐藏的 Textbox 来维护 NotAllowedCharacters。我将此隐藏 Textbox 的值传递给脚本。双引号("")内的字符将被视为已验证字符串。

唯一的条件是,如果您输入双引号("),它将无法正常工作。但我已经提供了解决方法。请看下面的代码。
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">");
}

您还可以设置 Enabled 和 Disabled 属性。在我们的页面生命周期场景中,当控件处于禁用模式时,控件的值不会保留。

因此,我没有禁用控件。而是设置了控件的只读属性,并更改了颜色使其看起来像禁用模式。
注意:此属性对所有控件都是通用的。

我继承了 IPostBackDataHandler 以便保留 Postback 数据。请看下面的代码。

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

IP Control 的代码说明
IP 控件总共包含 7 个 HtmlInputTextBox 控件 - 四个用于用户输入,其余用作分隔符。

在此控件中,我继承了 INamingContainer 接口,为每个控件创建唯一的 ID。
以下代码显示了控件是如何创建的。我重写了 CreateChildControls 方法来创建控件。
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);
}

以下属性用于获取和设置 IP 地址
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 方法确保当前控件拥有子控件。然后,它获取或设置当前控件的 ControlCollection 对象中子 Textbox 控件的 Text 属性。

Timer Control 的代码说明

为了构建此控件,我使用了三个 HtmlInputTextbox 和两个 HtmlButton 控件。我为开发人员提供了从 HourMinSec Timer 切换到 HourMin 以及反之亦然的选项。在此控件中,我使用了与上述控件相同的技术。
但我增加了一些额外功能,即UpDown 按钮的默认图像。因此,开发人员可以更改此属性来设置自己的图像。

我使用一个类来从属性窗口打开文件对话框。请看下面的代码。

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)|*.*";
    }
  }
}

我将上述类写在一个单独的类文件中(易于理解)。以下属性显示了我如何使用这些类。

[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 ;
  }
}

EditorAttribute 在属性窗口中放置了一个按钮。此按钮会启动文件对话框。我对选择 ClientSideScriptLocatin 属性也做了同样的处理。

这里也有一个问题 - 当我从默认值切换控件时,出现了一些设计问题和脚本错误。这是因为当您更改控件类型属性时,CreateChildControls 方法没有被触发。
因此,我显式地清除所有控件,并在更改控件类型时重新创建控件。请看下面的属性。

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;
  }
}

以下代码显示了如何为按钮设置默认图像。当您将控件拖放到表单上时,我会在您的应用程序路径中创建一个 Image 文件夹,并将图像放在该文件夹中。但在此之前,您的应用程序文件夹应具有写入权限。否则,将无法创建默认图像。

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;    }
}

UpDownNumeric Control 的代码说明

此控件的功能与我在 Timer 控件中所做的类似。
在此控件中,我添加了两个属性 MaxMin。开发人员可以设置最大最小值。利用此属性,开发人员可以限制用户的取值范围。
其他所有内容都与 Timer 控件相同。

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;
  }
}

我将我的 JavaScript 与本文一起发布。该脚本非常容易理解,无需任何解释。

关注点
我曾试图通过属性窗口显示样式生成器。目前我无法做到。我到处搜索过。但没有找到。如果您有任何关于增强控件以及如何整合样式生成器的想法,请发表。
这对我和其他需要相同功能的开发人员都非常有帮助。

© . All rights reserved.