从简单做起---ASP.NET复合控件(修定版)(注意在OnInit裡面設置好ID,否則無法在回傳時獲取控件值)
在你的网页应用程序里面添加用户控件,真的很简单。事实上,你只是做了网页的一部分,添加HTML,然后在应用程序里面使用。尽管用着很简单,但是不方便在应用程序间共享。有一种控件—复合性控件,做起来很复杂,但是用着很方便,它可以很方便地在不同的应用程序之间多次使用。这里我们就简单介绍这种控件的生成方法。
我们可以使用MS内置控件,如Textbox等来组建你的复合控件,当然,也可以用自己定义Layout。在这里我们放三个Textbox,让用户来输入日期,当然还有一些逻辑代码来合并这些日期成为一个完整的日期格式。
在这个DEMO中你要建两个工程,一个是复合控件工程Web Control Library,一个是引用这个复合控件的WEB程序。在这里,我们的前者工程叫做,DateEditBox,完成后,会有一个DateEditBox的类。以下这个类的主要信息:
 namespace MyControls
namespace MyControls {
{ [DefaultProperty("Value")]
   [DefaultProperty("Value")] [ToolboxData("<{0}:DateEditBox runat=server></{0}:DateEditBox>")]
   [ToolboxData("<{0}:DateEditBox runat=server></{0}:DateEditBox>")] public class DateEditBox : CompositeControl
   public class DateEditBox : CompositeControl {
   { private TextBox txtMonth = new TextBox();
      private TextBox txtMonth = new TextBox(); private TextBox txtDay   = new TextBox();
      private TextBox txtDay   = new TextBox(); private TextBox txtYear  = new TextBox();
      private TextBox txtYear  = new TextBox();
 protected override void OnInit(EventArgs e)
      protected override void OnInit(EventArgs e) {
      { base.OnInit(e);
         base.OnInit(e); txtMonth.ID        = this.ID + "_month";
         txtMonth.ID        = this.ID + "_month"; txtMonth.MaxLength = 2;
         txtMonth.MaxLength = 2; txtMonth.Width     = this.Width;
         txtMonth.Width     = this.Width;
 txtDay.ID        = this.ID + "_day";
         txtDay.ID        = this.ID + "_day"; txtDay.MaxLength = 2;
         txtDay.MaxLength = 2; txtDay.Width     = this.Width;
         txtDay.Width     = this.Width;
 txtYear.ID        = this.ID + "_year";
         txtYear.ID        = this.ID + "_year"; txtYear.MaxLength = 4;
         txtYear.MaxLength = 4; txtYear.Width     = this.Width;
         txtYear.Width     = this.Width; }
      }
 [Bindable(true)]
      [Bindable(true)] [Category("Appearance")]
      [Category("Appearance")] [DefaultValue("")]
      [DefaultValue("")] [Localizable(true)]
      [Localizable(true)] public DateTime Value
      public DateTime Value {
      { get
         get {
         { EnsureChildControls();
            EnsureChildControls(); if (txtMonth.Text == "" || txtDay.Text == "" ||
            if (txtMonth.Text == "" || txtDay.Text == "" || txtYear.Text == "")
                txtYear.Text == "") return DateTime.MinValue;
               return DateTime.MinValue; else
            else return new DateTime(Convert.ToInt32(txtYear.Text),
               return new DateTime(Convert.ToInt32(txtYear.Text), Convert.ToInt32(txtMonth.Text),
                  Convert.ToInt32(txtMonth.Text), Convert.ToInt32(txtDay.Text));
                  Convert.ToInt32(txtDay.Text)); }
         }
 set
         set {
         { EnsureChildControls();
            EnsureChildControls(); txtMonth.Text = value.Month.ToString();
            txtMonth.Text = value.Month.ToString(); txtDay.Text   = value.Day.ToString();
            txtDay.Text   = value.Day.ToString(); txtYear.Text  = value.Year.ToString();
            txtYear.Text  = value.Year.ToString(); }
         } }
      } protected override void CreateChildControls()
      protected override void CreateChildControls() {
      { this.Controls.Add(txtMonth);
         this.Controls.Add(txtMonth); this.Controls.Add(txtDay);
         this.Controls.Add(txtDay); this.Controls.Add(txtYear);
         this.Controls.Add(txtYear); base.CreateChildControls();
         base.CreateChildControls(); }
      } public override void RenderControl(HtmlTextWriter writer)
      public override void RenderControl(HtmlTextWriter writer) {
      { writer.RenderBeginTag(HtmlTextWriterTag.Table);
         writer.RenderBeginTag(HtmlTextWriterTag.Table); writer.RenderBeginTag(HtmlTextWriterTag.Tr);
         writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td);
         writer.RenderBeginTag(HtmlTextWriterTag.Td); txtMonth.RenderControl(writer);
         txtMonth.RenderControl(writer); writer.RenderEndTag();    // td
         writer.RenderEndTag();    // td writer.RenderBeginTag(HtmlTextWriterTag.Td);
         writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write("/");
         writer.Write("/"); writer.RenderEndTag();    // td
         writer.RenderEndTag();    // td writer.RenderBeginTag(HtmlTextWriterTag.Td);
         writer.RenderBeginTag(HtmlTextWriterTag.Td); txtDay.RenderControl(writer);
         txtDay.RenderControl(writer); writer.RenderEndTag();    // td
         writer.RenderEndTag();    // td writer.RenderBeginTag(HtmlTextWriterTag.Td);
         writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write("/");
         writer.Write("/"); writer.RenderEndTag();    // td
         writer.RenderEndTag();    // td writer.RenderBeginTag(HtmlTextWriterTag.Td);
         writer.RenderBeginTag(HtmlTextWriterTag.Td); txtYear.RenderControl(writer);
         txtYear.RenderControl(writer); writer.RenderEndTag();    // td
         writer.RenderEndTag();    // td writer.RenderEndTag();    // tr
         writer.RenderEndTag();    // tr writer.RenderEndTag();    // table
         writer.RenderEndTag();    // table }
      } }
   } }
}

这个类有点复杂,让我们来分析一下。我个内是以一些属性定义开始的。第一个是默认值,用来指定值的属性。第二个是用来指定本控件可以用在WEB页面的,一般是从VS工具箱拖拉到页面上的。你也注意到了,这个类是继承至CompositeControl,,这个内是专为自定义复合控件定制的。关于这个类的详细信息可以查看MSDN。
在OnInit事件里,我们给这三个子控件设置一些默认值,如ID,宽度,字长等。我们设置ID以复控件ID开头,是因为在后面我们将用这些ID来查找这些控件。
我们有值属性设置器,就可以很方便的设置和读取它们各自的值,当然,在这里,你完全可以加入一些基本的验证。在这里就不说这些了。接下来就是CreateChildControls方法和RenderControl方法。前者可以让页面在回传的时候保存控件状态。如果没有这方法,你的子控件就不能保存视图状态,所以也不能正常显示在回传页面的时候。后一个方法负责让你的控件在页面上正常显示。这样的话,你的控件就会显示以下格式:
 table
table tr
   tr td [txtMonth] /td
      td [txtMonth] /td td [/] /td
      td [/] /td td [txtDay] /td
      td [txtDay] /td td [/] /td
      td [/] /td td [txtYear] /td
      td [txtYear] /td /tr
   /tr /table
/table
当然在HtmlTextWriter里面你也可以自己定义你的样式,排版等。如果你想在其它工程中引用这个控件的话,首先要编译,成功后会在BIN里面出现*.dll,引用这个DLL在新的工程里面,然后,在你的页面代码里加入如下代码:
<%@ Register Assambly=”myControls” Namespace=”myControls” TagPrefix=”MC” %>
一旦在工程里添加DLL引用后,工程会自动COPY这个DLL到BIN目录里面,在你的VS智能感知里面会出现类如MC:DateEditBox,在后台代码里面,你可以看到控件的属性值。
总结:
你还可以添加更多的功能在这个控件里,但是这里只是显示最基本的控件需要代码。创建新的子控件,设置它们的ID值,添加到控件集合里,最后呈现出来。至此一个复合控件就完成了。之后,在添加更多的事件,属性和方法等,让你的控件看起来更酷一些。
P.S.大家可以注意到在这段代码里面有个EnsureChildControls()方法,在作者的原文中没有相关的说明,非常感谢wangzhe.king在这里提出问题,我想大多数朋友都不太清楚,这个方法,在此说明一下:
这个方法在检测当前ChildControlsCreated的值,如果是FALSE的话,那么就调用这个方法。ASP.NET调用这个方法,以保证子控件已经构建完毕。在大多数情况下,自定义服务器控件开发者不必重写这个方法。这个方法大多数用在属性器里面,因为在设置或得到属性值以前,你要检测子控件是否已经构建了。
官方详细解说,点此查看!
译自:CodeGuru 原文地址
 
                    
                     
                    
                 
                    
                
 
    
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号