ASP.NET服务器控件的开发(1)

3.1          System.Web.UI.Control类介绍

 

3.1.1     Render方法

 

    基类System.Web.UI.Control最重要的方法是Render,代码如下:

          protected virtual void Render(HtmlTextWriter writer)
  
  
          {
  
  

                    this.RenderChildren(writer);

          }

它允许为一个HtmlTextWriter对象提供服务器控件的内容,并把内容输出到客户设备上。开发服务器控件时,我们可以重写该方法生成ASP.NET页面的内容

     在它的执行体中只有一行代码,调用了RenderChildren方法,该方法的作用是呈现该控件下的所有子控件。RenderChildren中的参数是HtmlTextWriter类。

     这里我们来简单介绍下System.Web.UI.HtmlTextWriter类,HtmlTextWriter类允许编写HTML内容和文本,我们来看一下HtmlTextWriter类的重要方法(表3-1)

3-1

AddAttribute

允许在HtmlTextWrite输出流中添加HTML特性和值

AddStyleAttribute

允许在HtmlTextWrite输出流中添加HTML样式特性

WriteAttribute

允许在HtmlTextWrite输出流中写一个HTML特性

RenderBeginTag

允许写一个HTML元素开始标记到输出流中

RenderEndTag

允许写一个结束标记到输出流中

WriteBeginTag

RenderBeginTag方法类似,不同的是不能为元素写结束字符”>”

WriteEndTag

允许写一个已用RenderBeginTag方法写好的HTML元素的结束标记

Write

允许将值直接写入输出流

 

下面我们来看一个重写Render方法创建服务器控件的例子(例3-1),代码如下:

3-1

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.ComponentModel;

 

namespace WebControlLibrary3

{

     [DefaultProperty("Text"),

         ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]

     [ParseChildren(false)]  //将子XML元素视为子控件

     public class WebCustomControl1 : System.Web.UI.Control

     {

          private string text;

         [Bindable(true),

              Category("Appearance"),

              DefaultValue("")]

         public string Text

         {

              get

              {

                   return text;

              }

              set

              {

                   text = value;

              }

         }

         protected override void Render(HtmlTextWriter writer)

         {

              writer.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Type,"text");

              writer.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Class,"class1");

              writer.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Name,"text1");

              writer.AddAttribute(System.Web.UI.HtmlTextWriterAttribute.Value,this.Text);

              writer.AddStyleAttribute(System.Web.UI.HtmlTextWriterStyle.Height,"30");

              writer.AddStyleAttribute(System.Web.UI.HtmlTextWriterStyle.Width,"160");

              writer.AddStyleAttribute(System.Web.UI.HtmlTextWriterStyle.FontSize,"24");

              writer.RenderBeginTag(System.Web.UI.HtmlTextWriterTag.Input);

              writer.RenderEndTag();     

         }

     }

}

 

控件的调用代码:

<%@ Register TagPrefix="cc1" Namespace="WebControlLibrary3" Assembly="WebControlLibrary3" %>

……

……

……

<cc1:WebCustomControl1 id="WebCustomControl11"  Text=”test”  runat="server" >

<asp:Button id="Button1" runat="server" Text="Button" Width="104px" Height="32px"></asp:Button>

</cc1:WebCustomControl1>

 

显示结果如图(图3-1)

3-1

 

 [ParseChildren(false)]这个属性是设置将子XML元素视为控件的属性还是视为子控件

     在这个例子中我们没有调用RenderChildren方法,所以该控件下的所有子控件都不会被呈现,所以在ASPX页的控件中添加<asp:Button id="Button1" runat="server" Text="Button" Width="104px" Height="32px"></asp:Button>是没用的,当我们在Render执行体中中调用RenderChildren方法

         protected override void Render(HtmlTextWriter writer)

         {

              ……

              writer.RenderEndTag();     

              RenderChildren(writer);

         }

 

那么显示结果就不同了,如图(图3-2)

3-2

     看了这个例子你应该会感到编写服务器控件其实也很简单吧!

 

3.1.2     CreateChildControls方法

 

    基类System.Web.UI.Control另一个重要的方法是CreateChildControls方法,代码如下:

          protected virtual void CreateChildControls()

          {

          }

该方法没有任何的执行体,我们可以重写该方法为控件添加子控件,下面我们先来看一个例子(例3-2)

3-2

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.ComponentModel;

 

namespace WebControlLibrary4

 

     [DefaultProperty("Text"),

         ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]

     public class WebCustomControl1 : System.Web.UI. Control

     {

         private string text;

         [Bindable(true),

              Category("Appearance"),

              DefaultValue("")]

         public string Text

         {

              get

              {

                   return text;

              }

              set

              {

                   text = value;

              }

         }

 

         protected override void CreateChildControls()

         {

              TextBox textBox1=new TextBox();

              textBox1.Text=this.text;

              this.Controls.Add(textBox1);  //为控件添加子控件

         }

     }

}

控件的调用代码:

<%@ Register TagPrefix="cc1" Namespace="WebControlLibrary4" Assembly="WebControlLibrary4" %>

<cc1:WebCustomControl1 id="WebCustomControl11"  runat="server"  Text="例3-2">

</cc1:WebCustomControl1>

显示结果如图(图3-3)

3-3

    在这个例子中我们通过重写CreateChildControls方法为控件添加了TextBox控件,

this.Controls.Add(textBox1)该语句是把TextBox控件添加到我们创建的服务器控件的子控件列属性中,这样我们才可以在页面显示该子控件的内容。

3.1.3     Control类其他方法介绍

 

     RaiseBubbleEvent方法可被派生类调用,把事件提升到控件层次结构上,发送给它的命名容器,该方法在基本控件类Control中的代码如下:

protected void RaiseBubbleEvent(object source, EventArgs args)

{

      for (Control control1 = this._parent; control1 != null; control1 = control1.Parent)

      {

            if (control1.OnBubbleEvent(source, args))  //触发父控件的OnBubbleEvent方法

            {

                  return;

            }

      }

}

调用该方法我们可以触发父控件的OnBubbleEvent方法,该方法我们将在下面介绍

我们先来看下Button控件OnCommand方法的代码:

protected virtual void OnCommand(CommandEventArgs e)

{

      CommandEventHandler handler1 = (CommandEventHandler) base.Events[Button.EventCommand];

      if (handler1 != null)

      {

            handler1(this, e);  //触发Command事件

      }

      base.RaiseBubbleEvent(this, e);  //将事件提升到控件层次结构上

}

Button控件的OnCommand方法中调用了控件基本类的RaiseBubbleEvent方法,当Button控件做为其他可以接收事件提升的控件的子控件时, RaiseBubbleEvent方法调用了父控件的OnBubbleEvent方法,传递的参数是在RaiseBubbleEvent方法中指明的

 

     OnBubbleEvent方法是用来捕获从子程序提升的事件,只被派生类调用,该方法在基本控件类Control中的代码如下:

protected virtual bool OnBubbleEvent(object source, EventArgs args)

{

      return false;

}

该方法是在子控件的RaiseBubbleEvent方法中被调用的,传递的参数也就是子控件RaiseBubbleEvent方法中的2个参数。

我们可以重写该方法接收提示事件的通告,通过检查事件参数来获取它们的类型和事件类型,并求解参数的内容,决定采取什么动作。

     OnBubbleEvent方法有个Boolean返回值,这个返回值指示提升事件是否已被处理。因此控件能够处理某个被提升的事件,并允许其他事件继续提升到控件层次结构上,当返回值为true时表明提升的事件已被处理,事件将不会被继续提升到控件的父控件中,当返回值为false时,事件将继续被提升。

 

     EnsureChildControls方法可被派生类调用来保证子控件被创建,同时设定ChildControlsCreated属性的值为true。当ChildControlsCreated属性为true时,CreateChildControls方法将不会被再次自动调用。
  
  

 

     RenderChildren方法在第一节我们已经有提到,该方法一般在重写Render方法时被调用,保证控件的子控件内容被输出到提供的System.Web.UI.HtmlTextWriter对象,从而在页面呈现子控件。

 

        LoadViewState方法在控件被初始化后调用。该方法的作用是使用__VIEWSTATE隐藏表单域提交的名-值数据对生成ViewState属性包,该属性我们会在下面介绍。

 

        SaveViewState方法在生成__VIEWSTATE隐藏表单域之前被调用可以修改服务器控件的ViewState属性。该方法与LoadViewState方法结合使用,我们重写这2个方法可以自定义在服务器控件中创建,管理和保存状态的方法。

 

     DataBind方法OnDataBinding方法,这两个方法与数据绑定有关,这里我们先不做分析,在下面的数据绑定一节我们会对这两个方法进行讲解

 

3.1.4     Control类的主要属性

 

     Controls属性,该属性是只读的,可以被继承重写。在3-2中我们已经用到了该属性,通过该属性值的Add方法我们可以为控件添加子控件。添加代码如Controls.Add(textBox1);我们将一个名字为textBox1的TextBox控件添加进了当前控件的子控件列中。

     Parent属性,该属性是只读的,可以被继承重写。通过该属性我们可以得到当前控件的父控件。也许有人会问既然这个属性是只读的,那该属性是怎么被设置的呢?其实不用我们人为设置,Control类有一个名为_parent的私有成员,当我们调用Controls.Add(textBox1);textBox1子控件添加时,自动会把当前控件设置为textBox1控件的父控件的,所以我们只要把textBox1添加为当前控件的子控件,我们就可以直接用Parent属性得到textBox1控件的父控件。

NamingContainer属性该属性是只读的,可以被继承重写。通过该属性我们可以得当当前控件的命名容器,也就是一个继承了INamingContainer接口的父控件。

     Visible属性,该属性的默认值为true,即控件内容会呈现在页上,当我们设置该属性为false时,控件将不会在页面上显示。
  
  
     ChildControlsCreated属性,通过该属性我们可以设置或获取自控件是否已被创建,例如我们在方法中设置了ChildControlsCreated属性为true那么CreateChildControls方法将不会被再次调用,我们再做可数据绑定的控件时该属性将非常有用。
  
  
     ViewState属性,该属性我们将再下面分节讲(3.1.5节)
  
  

  
  

  
  
3.1.5     ViewState
   
   

   
   
     ViewState是控件类的一个属性,属于保护成员,可以被继承访问,类型为StateBag类型,存储名-值对,他们一般用在回送中存储控件属性的值。
  
  
     看起来该属性好象是一个新技术,其实只是以旧创新,只是在控件执行周期的最后将ViewState中的信息以一个HTML隐藏表单控件__VIEWSTATE写到客户机上。
  
  
     所以在ASPX页面呈现代码里我们可以看到隐藏表单语句如下:
  
  
<input type="hidden" name="__VIEWSTATE" value="dDwtODExODIwMDE1Ozs+m9YKwTpuJ4WsxzTv5/6V2+2RvFE=" />
  
  
     在回送时,这个信息从__VIEWSTATE隐藏表单控件读出,继续以ViewState名-值对的形式保存。
   
   
下面我们用2个例子来做下对比说明(例3-3和例3-4)
   
   
3-3:
    
    

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.ComponentModel;

namespace WebControlLibrary4

{

     [DefaultProperty("Text"),

         ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]

     public class WebCustomControl1 : System.Web.UI.Control

     {

         [Bindable(true),

              Category("Appearance"),

              DefaultValue("")]

         public string Text

         {

              get

              {

                   if(this.ViewState["text"]==null)

                   {

                       this.ViewState["text"]="初始值";

                   }

                   return ViewState["text"].ToString();

              }

              set

              {

                   this.ViewState["text"]=value;

              }

         }

         protected override void Render(HtmlTextWriter writer)

         {

              writer.AddAttribute(HtmlTextWriterAttribute.Type,"text");

              writer.AddAttribute(HtmlTextWriterAttribute.Name,this.UniqueID);

              writer.AddAttribute(HtmlTextWriterAttribute.Value,this.Text);

              writer.RenderBeginTag(HtmlTextWriterTag.Input);

              writer.RenderEndTag();

         }

     }

}
  
  
控件的调用代码:
   
   
<%@ Register TagPrefix="cc1" Namespace="WebControlLibrary4" Assembly="WebControlLibrary4" %>
  
  
……
   
   
<cc1:WebCustomControl1 id="WebCustomControl11" runat="server"></cc1:WebCustomControl1>
  
  
<asp:Button id="Button1" style="Z-INDEX: 101; LEFT: 48px; POSITION: absolute; TOP: 64px" runat="server" Text="Button" Width="72px"></asp:Button>
  
  
<asp:Button id="Button2" style="Z-INDEX: 102; LEFT: 64px; POSITION: absolute; TOP: 128px" runat="server" Text="Button2" Width="80px"></asp:Button>
  
  
后置代码如下:
   
   

省略……

namespace WebApplication11

{

     public class WebForm1 : System.Web.UI.Page

     {

         protected WebControlLibrary4.WebCustomControl1 WebCustomControl11;

         protected System.Web.UI.WebControls.Button Button2;

         protected System.Web.UI.WebControls.Button Button1;

省略……

         private void InitializeComponent()

         {   

              this.Button1.Click += new System.EventHandler(this.Button1_Click);

         }

         private void Button1_Click(object sender, System.EventArgs e)

         {

              WebCustomControl11.Text="test";

         }

     }

}
  
  
看下运行结果,如图(图3-4)
   
   
3-4
    
    

   
   
    
    
 
    
    

   
   
   
   
当我们点击Button显示如图(图3-5)
   
   
3-5
    
    

   
   
    
    
 
    
    

   
   
   
   
当我们再点击Button2显示结果不变,仍为图3-5所示
   
   
     再来让我们看看例3-4,仔细观察下他们代码的区别。
   
   
3-4:
    
    

//以上代码如例子1-3不变

     public class WebCustomControl1 : System.Web.UI.Control

     {

         private string text="初始值";

         [Bindable(true),

              Category("Appearance"),

              DefaultValue("")]

         public string Text

         {

              get

              {

                       return this.text;

              }

              set

              {

                   this.text=value;

              }

         }

//以下代码如例子3-3不变

我们对例3-3做了下小小的修改,在这里我们没有使用ViewState["text"]保存信息,那么显示结果会怎样呢?看看吧(图3-6)
  
  
3-6
    
    

   
   
    
    
 
    
    

   
   
   
   
没区别啊!!!
   
   
点击下Button如图(图3-7)
   
   
3-7
    
    

  
  
   
   
 
   
   

  
  
  
  
还是,没区别啊!!!
   
   
我们最后再点击下Button2如图(图3-8)
   
   
3-8
    
    

   
   
    
    
 
    
    

   
   
   
   
呀,怎又变成图3-6的样子了啊?
   
   
     其实例3-3与例3-4的区别就在这里,因为例3-3我们使用了ViewState属性以名-值对的方式来存储Text属性的值,所以当我们点击Button2按扭的时候代码
   
   
writer.AddAttribute(HtmlTextWriterAttribute.Value,this.Text);
  
  

读取的Text属性其实是ViewState["text"]值,该值是由隐藏表单控件__VIEWSTATE回送回来的,而例3-4没有使用ViewState属性保存信息,所以当点击Button2按扭时读取的Text属性其实时私有字符串变量text的初始值。

    当我们做可以供用户提交的控件时该属性时非常有用的,可以保存用户输入的信息,具体什么时候用,怎么用还是要仔细琢磨的。

 

3.1.6          Control类的主要事件

 

     Control类中定义了6个事件Init,Load,Unload,DataBinding,PreRender和Disposed。看名字应该能猜到他们有什么用,在什么时候触发的吧。这6个事件的触发函数分别为OnInit,OnLoad,OnUnload,OnDataBinding,OnPreRender和Disposed。这6个方法都可以被继承重写,一般我们在编写控件时会重写OnInit方法来实例化我们的子控件,要记住我们最好不要重写OnLoad方法来实例化我们的子控件,因为OnLoad方法在控件被加载时都会调用一次,这样每次都会对子控件进行new,这样子控件的信息讲无法被保存,而OnInit方法就不一样了,大家可以自己试下。
   
   
    DataBinding事件载数据绑定时会被触发,页就是在调用DataBind方法时被触发,在数据绑定节我们会用到DataBinding事件的触发函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值