代码改变世界

asp.net控件开发基础(4)

2006-08-05 16:16  Clingingboy  阅读(21622)  评论(18编辑  收藏  举报
       上一篇写了有关回传的一些东西,这次我本来不知道该写什么的,因为各方面的关联太多了,最后我还是想,还是慢慢一点点的写吧.这次讲WebControl

一.从继承WebControl开始

在第二篇教程中,重点介绍了Render()方法的使用,用来呈现控件,但从Control类继承的控件尚未发挥asp.net控件的作用.大家知道web服务器控件分为HTML服务器控件(如<input id="Button2" runat="server" type="button" value="button" />这样的形式)和标准服务器控件(就是<asp:..  id="" runat="server" />这样的形式的控件)

HTML服务器控件的控件从System.Web.UI.HtmlControls.HtmlControl 类派生

标准服务器控件的控件从System.Web.UI.WebControls.WebControl 类派生

HtmlControl 类和WebControl 类则从System.Web.UI.Control 类派生,并扩展.

所以我们说,所有的服务器控件都继承自System.Web.UI.Control 类,即所有的服务器控件都具有Control 类的共同属性,如Visible,EnableViewState属性,HtmlControl 类和WebControl 类则扩充了System.Web.UI.Control 类的功能,如

HtmlControl 类定义了所有 HTML 服务器控件所通用的方法、属性 (Property) 和事件(具体参数参照MSDN)

WebControl 类定义了所有 标准服务器控件所通用的方法、属性 (Property) 和事件(具体参数参照MSDN)

如每个继承了WebControl 类的标准控件都有定义外观和行为的属性,然后不同控件再根据需要扩展功能.

图一

所以我们推荐的做法是直接从WebControl 类派生,而非Control类.我们所做的非并从头开始.从WebControl 类继承可以帮我们省很多工作.

二.重写WebControl类方法,不再是Render()

WebControl类继承了Control类,当然有Render方法,在WebControl类中重写了Render方法,如下代码

示例一
protected override void Render(HtmlTextWriter output)
{
 RenderBeginTag(output);
 RenderContents(output);
 RenderEndTag(output);
}

注意 RebderBeginTag方法并非是HtmlTextWriter类中的方法,而是WebControl类中的方法,表示输出HTML标签头标记,如<table .....>,RenderEndTag方法则输出HTML标签尾标记,如</table>.中间的RenderContents方法则就是Control类的Render方法.
看下面RenderContents方法的定义.

示例二
protected override void RenderContents(HtmlTextWriter output)
 
//使用默认逻辑来呈现子控件,那么一定要调用基类中的方法。 
 base.Render(output);
}


接着再看RenderBeginTag方法的定义

示例三
      public virtual void RenderBeginTag(HtmlTextWriter output)
      
{
          
//添加呈现控件的属性和样式
          
//AddAttributesToRender为WebControl类中的方法
          AddAttributesToRender(output);
          
//呈现控件标签
          
//如label控件呈现<span >
          
//textbox控件呈现<input >
          HtmlTextWriterTag tagKey = TagKey;
          
if (tagKey != HtmlTextWriterTag.Unknown)
          
{
              output.RenderBeginTag(tagKey);
          }

          
else
          
{
              output.RenderBeginTag(
this.TagName);
          }

      }

这里打个比方,假设你要输出一个表格,你就必须定义<table>标签头,然后在其内部定义<tr>,<td>,下面看Control类中Render方法的实现,表明Render方法必须完成所有的任务,包括标签头标记<table>和<table>标签的属性和样式的输出.

示例四
        protected override void Render(HtmlTextWriter writer)
        
{
            
//为table标签定义属性和样式
            writer.AddAttribute(HtmlTextWriterAttribute.Width, "287px");
            writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, 
"0");

            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(
"<strong>" + PaymentMethodText + "</strong>");
            writer.RenderEndTag();
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, 
"PaymentMethod");
            writer.AddAttribute(HtmlTextWriterAttribute.Id, 
"PaymentMethod");
            writer.AddStyleAttribute(HtmlTextWriterStyle.Width, 
"100%");
            writer.RenderBeginTag(HtmlTextWriterTag.Select);

            
//以下代码省略
        }


在WebControl类中重写了Render方法后,直接帮你定义好了标签,默认情况下为<span>,可通过重写TagKey属性来修改标签,然后AddAttributesToRender方法为标签定义样式和属性

示例五
    protected override HtmlTextWriterTag TagKey
    
{
      
get return HtmlTextWriterTag.Table; }
    }

示例六
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        
{
            
//为table标签定义属性和样式
            writer.AddAttribute(HtmlTextWriterAttribute.Width, "287px");
            writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, 
"0");

            
base.AddAttributesToRender(writer);

        }


接着重写RenderContents方法,对比上面的Render方法,实现效果是一样的

示例七
    protected override void RenderContents(HtmlTextWriter writer)
    
{
      
//注意,此处无没有table标签,只定义其内部标签
      writer.RenderBeginTag(HtmlTextWriterTag.Tr);
      writer.RenderBeginTag(HtmlTextWriterTag.Td);
      writer.Write(PaymentMethodText);
      writer.RenderEndTag();
      writer.RenderBeginTag(HtmlTextWriterTag.Td);
      writer.AddAttribute(HtmlTextWriterAttribute.Name, PaymentMethodSelectName);
      writer.AddAttribute(HtmlTextWriterAttribute.Id, PaymentMethodSelectId);
      writer.AddStyleAttribute(HtmlTextWriterStyle.Width, 
"100%");
      writer.RenderBeginTag(HtmlTextWriterTag.Select);
      
//以下省略

    }


所以说重写后的Render方法在默认情况下加了一个标签,而你可以重写这个标签(默认情况下为<span>).可能大家对其感到奇怪,即然可以实现同样效果,有必要重写Render方法,再加一个RenderContents方法吗?

三.Render方法和RenderContents方法的区别

当你继承WebControl类,在RenderContents方法中实现示例四代码时,(我们再以以前的例子展示)呈现后的代码如下,看到没有,控件ID为<span>
在RenderContents方法输入的标签将成为其内部标签.再看看这个控件的属性面板,你会看到很多的继承自WebControl类的属性,设置其属性,即是设置<span>标签的属性.TagKey的作用大概就在于此吧,为了使用WebControl类的公共属性.(我是这么认为的)而非定义在<table>标签上
示例八
<span id="CreditCardForm5_1"><table style="border-width:0;">
    
<tr>
        
<td><strong>信用卡类型</strong></td><td><select name="PaymentMethod" id="PaymentMethod" style="width:100%;">
......


假设我们称<span>里面的<table>等标签为子标签,在RenderContents方法应该定义控件的子标签,如果你只定义标签属性的话,只需重写AddAttributesToRender方法即可,可不须重写RenderContents方法.

下面再讲下重写标签的方法

(1) 重写TagKey属性,下面重写label控件的标签

  public class Ch4Label: Label
    
{
        
protected override HtmlTextWriterTag TagKey
        
{
            
get return HtmlTextWriterTag.Div; }
        }

    }

(2)重写基类构造函数,此方法只有在继承Control类后适用

public CreditCardForm5() : base(HtmlTextWriterTag.Table) { }


最后总结下:
1.控件继承自WebControl类                    主要原因是WebControl类公共的东西比Control类
2.TagKey                                                   表示控件的标签,默认情况下为<span>,可以重写此属性修改或者重写WebControl类的构造函数
3.AddAttributesToRender方法                  为标签添加属性和样式
4.RenderContents方法                               在标签内呈现内容

如果控件不复杂,则可直接从标准控件继承(如label),再根据需要扩展,重写AddAttributesToRender方法,还可以重写
TagKey更改默认标签,而无须重写RenderContents方法.如果控件比较复杂,不是单一的,则需要在RenderContents方法输出控件的内部的内容.

其实最大的区别就是默认情况下WebControl类为你加了一个标签,方便添加WebControl类的一些公共的东西,如果你重写Render()方法,而舍弃RenderContents方法,你就无福享受WebControl类给你提供的这么多属性和方法了.

大家多熟悉下WebControl类的一些公共属性,然后再多改改,可以明白的更加深刻.

我喜欢慢慢的把东西全讲全,不然心里不舒服,所以我就慢慢写了,当然前提是我理解的基础上.这次的例子,大家可根据第二篇的代码适当修改就可.错误之处还请指出^_^

参考文章:http://dev.yesky.com/msdn/37/2416037.shtml