`
lovnet
  • 浏览: 6686846 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—(3)从零开始开发服务器控件】★★★

阅读更多
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

3庖丁解牛系列—从零开始开发服务器控件

本章内容

3.1 选择基类

3.2 控件呈现顺序

3.3 Render呈现控件的几种方式

3.4 AddAttributesToRender方法

3.5 CreateChildControls方法

3.6 INamingContainer接口

3.7 实现复合控件

3.8 常用开发技巧

[点击下载本书word格式完整目录介绍]

3.1 选择基类

在开发一个控件之前要先选择控件开发要继承的基类,这些基类封装了控件最基本的功能,可以提高代码重用性,并且每个基类提供的功能不同,在第1章中已经列出了许多常用基类,如果您还不大清楚,请看一下第1章。

u 这里仅谈一谈一般开发基本控件所选择基类的方式。

Ø Control

控件开发基类,所有控件都直接或间接继承该类。提供了各类控件通用属性和方法,如唯一标志ID属性、可见性Visible等。

该类仅具有控件最基本的属性,扩展灵活性最强。

Ø WebControl

WebControl除了继承了Control的所有属性,还增加了布局、可访问性、外观样式等特性;另外,对行为也扩充了好多属性。

ControlWebControl都用于开发简单控件(即单个控件或非组件控件)。一般在选择控件时,如果要开发的控件对外观布局和样式等控件特性要求比较高,则可以选择继承WebControl要方便得多;反之,选用Control实现即可。如果一定要选用Control实现WebControl的特性也是可以的,但要自己增加所需的属性,如布局属性widthheight,实现起来会较麻烦。

一般在基于Web的系统中用得最多,扩展灵活性也很强。

Ø CompositeControl

此类为ASP.NET 2.0版本时已经支持的一个控件基类。如果把现有控件聚合起来创建一个组合控件时,可以继承此类,此类默认实现了INamingContainer接口,并且对设计模式表现有较好的支持。后面会详细介绍其创建方法。一般用于将具有一定功能的多个控件集成为一个控件的情况。

Ø 继承现有控件

把具有一定功能的成型控件,如LabelButton,甚至GridView等控件,作为新控件的基类,并在此基础上扩展或改变(通过override重载其方法实现)其功能,满足业务需要。

一般情况下开发一个基于Web平台的控件,比较常用的方法是从WebControl继承;本章主要讲开发一个控件的过程。就以继承WebControl为例来展开讲解。

只要是Web控件,不管是ASP.NET控件还是第三方厂商控件,最终被解析到客户端的都是标准的HTML标记。也可以这么说,做一个控件的过程就是根据控件使用者设置控件的属性(简单值或复杂数据源集合等)进行组织HTML并输出的过程。控件无非就是把一些常用的功能抽象成一个通用的控件,提高重用性,节省开发时间,这样要比之前开发人员对每个页面用纯HTML开发要好多了。

控件开发可以理解为组织HTML的过程。当然ASP.NET控件开发技术提供了一些规则,用多种方式有效地组织输出这些HTML标记,对样式、资源文件封装等也提供了一些帮助类和功能支持,下面我们就一起来看一下组织HTML标记的方式。

3.2 控件呈现顺序

控件生命周期的Render阶段,主要将控件标记和字符文本输出到服务器控件输出流中。在这个阶段可以直接写HTML标记,也可以调用每个控件都有的RenderControl方法到输出流。在WebControl基类中,以Render开头的呈现方法有如下几个:

  1. ØRenderControl(HtmlTextWriterwriter)
  2. ØRender(HtmlTextWriterwriter)
  3. ØRenderBeginTag(HtmlTextWriterwriter)
  4. ØRenderContents(HtmlTextWriteroutput)
  5. ØRenderEndTag(HtmlTextWriterwriter)

以上几个

Render方法并不是毫无联系的,它们的执行顺序是从上往下,并且有嵌套的调用关系。其中在RenderControl方法内部会调用Render方法,在Render方法内部会依次调用RenderBeginTag, RenderContentsRenderEndTag

其中RenderControlRenderControl基类中的方法,因为WebControl本身也是继承Control的。一般在开发基本控件时,我们只需重写RenderContents方法即可,在此方法中可以把控件HTML文本标记和其他内容写到输出流中。

另外,还有两个可以重载的方法 RenderBeginTagRenderEndTag。这两个方法执行时刻点是分别在Render控件内容之前和之后。可以重写这两个方法自己定义控件的起始和结束标记。默认情况下控件是以<Span></Span>作为起始和结束标记的,图3-1是没有重写标记的一个控件的默认显示。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f" o:preferrelative="t"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 269.25pt; HEIGHT: 80.25pt" type="#_x0000_t75" o:borderrightcolor="this" o:borderbottomcolor="this" o:borderleftcolor="this" o:bordertopcolor="this"><imagedata src="file:///D:%5CDOCUME~1%5CZHENGJ~1%5CLOCALS~1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image001.png" o:title=""></imagedata><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" /><bordertop type="single" width="4"></bordertop><borderleft type="single" width="4"></borderleft><borderbottom type="single" width="4"></borderbottom><borderright type="single" width="4"></borderright></shape>

3-1 控件默认标记是<Span></Span>

下面以一个例子来演示使用上面几个Render方法。新建一个RenderOrderControl.cs Web控件类,重载以下几个方法,并填充相应语句。代码如下所示:

  1. ///<summary>
  2. ///获得本书更多内容,请看:
  3. ///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
  4. ///</summary>
  5. ///<summary>
  6. ///Render方法执行顺序:3
  7. ///</summary>
  8. publicoverridevoidRenderBeginTag(HtmlTextWriterwriter)
  9. {
  10. //base.RenderBeginTag(writer);
  11. writer.AddAttribute(HtmlTextWriterAttribute.Id,this.ID);
  12. writer.RenderBeginTag(HtmlTextWriterTag.Div);
  13. }
  14. ///<summary>
  15. ///Render方法执行顺序:4
  16. ///</summary>
  17. protectedoverridevoidRenderContents(HtmlTextWriteroutput)
  18. {
  19. output.Write(Text);
  20. }
  21. ///<summary>
  22. ///Render方法执行顺序:5
  23. ///</summary>
  24. publicoverridevoidRenderEndTag(HtmlTextWriterwriter)
  25. {
  26. //base.RenderEndTag(writer);
  27. writer.RenderEndTag();
  28. }

上面代码仅呈现出控件Text属性文本。另外,重写了控件起始和结尾标签。呈现到浏览器中的控件如图3-2所示。

<shape id="_x0000_i1026" style="WIDTH: 271.5pt; HEIGHT: 93pt" type="#_x0000_t75" o:borderrightcolor="this" o:borderbottomcolor="this" o:borderleftcolor="this" o:bordertopcolor="this"><font size="2"><font color="#000000"><imagedata src="file:///D:%5CDOCUME~1%5CZHENGJ~1%5CLOCALS~1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image003.png" o:title=""></imagedata><bordertop type="single" width="4"></bordertop><borderleft type="single" width="4"></borderleft><borderbottom type="single" width="4"></borderbottom><borderright type="single" width="4"></borderright></font></font></shape>

3-2 控件重写标记为<div></div>

另外,读者可能注意到在RenderBeginTagRenderEndTag方法中有:

  1. base.RenderEngTag(writer);

这里跟面向对象继承是一个概念,表示调用基类中的方法,当继承于某个控件,扩展功能时常用到这样的方法。有以下几种处理方式:

1)复制基类方法功能:直接调用base.Method()方式,不加任何代码。

2)扩展基类方式功能:除了调用base.Method()之外,增加自己的扩展功能代码,并且base.Method()在方法体中的位置可以根据需要任意放置。

3)替换基类方法功能:不调用base.Method(),并增加自己需要的新功能代码。

4)取消重载规则:使用new关键字代替override,这样仅保证方法名是相同的,其内部执行逻辑可以由自己任意组织,用于面向对象编程中实现与基类中毫无相关的功能。

5)禁用基类方法功能:保留一个空的方法体。

说明:在本书讲解过程中的每一个例子都会有完整示例代码,对应于本书配套光盘的相关章节。

3.3 Render呈现控件的几种方式

3.3.1 使用HtmlTextWriter类输出

先看一个例子,其功能是输出一个超链接控件:

  1. ///<summary>
  2. ///获得本书更多内容,请看:
  3. ///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
  4. ///</summary>
  5. protectedoverridevoidRenderContents(HtmlTextWriteroutput)
  6. {
  7. //方式
  8. output.AddAttribute(HtmlTextWriterAttribute.Href,"http://www.cnblogs.com/");
  9. output.AddAttribute(HtmlTextWriterAttribute.Target,"blank");
  10. output.AddStyleAttribute(HtmlTextWriterStyle.Color,"Blue");
  11. output.AddStyleAttribute(HtmlTextWriterStyle.Cursor,"Hand");
  12. output.RenderBeginTag(HtmlTextWriterTag.A);
  13. output.Write(this.Text);
  14. output.RenderEndTag();
  15. output.WriteBreak();
  16. }

RenderContents

方法的参数类型为HtmlTextWriter,是具有呈现标记和其他HTML标记(包括HTML变量)的方法的实用工具类。该类能将控件的字符和文本标记等写入到服务器控件输出流中。并且此类在运行期间会自动生成实例。

Output.AddAttribute方法生成控件的属性,它有许多重载方法,可以直接以字符串形式把属性名称和属性值写入到输出流,也可以使用HtmlTextWriterAttribute枚举,帮助输入控件属性,如下都是使用AddAttribute方法的一些例子:

  1. ///<summary>
  2. ///获得本书更多内容,请看:
  3. ///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
  4. ///</summary>
  5. output.AddAttribute(HtmlTextWriterAttribute.Accesskey,"n");
  6. output.AddAttribute("Accesskey","n");
  7. output.AddAttribute(HtmlTextWriterAttribute.Bgcolor,"#6699ff");
  8. output.AddAttribute("bgcolor","#6699ff");
  9. output.AddAttribute(HtmlTextWriterAttribute.Checked,"true");
  10. output.AddAttribute("checked","true");
  11. output.AddAttribute(HtmlTextWriterAttribute.Class,"TextBoxStyleName");
  12. output.AddAttribute("class","TextBoxStyleName");
  13. output.AddAttribute(HtmlTextWriterAttribute.Onclick,"alert('Hello');");
  14. output.AddAttribute("onclick","alert('Hello');");
  15. output.AddAttribute(HtmlTextWriterAttribute.ReadOnly,"true");
  16. output.AddAttribute("readonly","true");
  17. output.AddAttribute(HtmlTextWriterAttribute.Tabindex,"5");
  18. output.AddAttribute("tabindex","5");

不用多说,仅通过这些例子读者就能够理解

AddAttribute方法和HtmlTextWriterAttribute枚举的用途了。其中AddAttribute方法除了能够为控件增加一般属性外,还能够增加客户端事件属性,如上面例子中的“onclick”属性。

HtmlTextWriterAttribute枚举包含了几乎所有控件的属性标记,同时也要求使用者了解不同的控件具有一些不同的属性标记,在知道要添加的控件具有某个枚举值的情况下才为其增加某个属性标记,避免把控件弄成“驴头对马身”情况。

Output.AddStyleAttribute方法生成控件的样式属性,像style="width:100%;" 中的width就是样式属性标记。同样使用HtmlTextWriterStyle枚举也可以帮助快速输入样式属性标记。通过如下示例了解一下它的功能:

u 本例中AddStyleAttributeHtmlTextWriterStyle与前面的AddAttributeHtmlText WriterAttribute用法一样。它们的区别也可以用一个例子来演示:

  1. <divid="div1"align="center"style="border-color:Blue"></div>

其中蓝色属性

align="center" 就是用AddAttribute方法输出的位置;粉红色样式属性style="border-color:Blue" 就是使用AddStyleAttribute方法输出的位置,样式属性嵌套在复合属性style中。一般属性(AddAttribute方法增加的属性)与样式属性(AddStyleAttribute方法增加的属性)有些具有相同功能的标记,比如,既可以使用一般属性也可以使用样式属性给控件设置背景色,但它们作用于控件的优先级是不一样的。

还有一对很重要且常用的方法RenderBeginTag和枚举HtmlTextWriterTag。下例演示了它们的功能:

/// <summary>

/// 获得本书更多内容,请看:

/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx

/// </summary>

output.RenderBeginTag(HtmlTextWriterTag.A);

output.RenderBeginTag("A");

output.RenderBeginTag(HtmlTextWriterTag.Button);

output.RenderBeginTag("button");

output.RenderBeginTag(HtmlTextWriterTag.Div);

output.RenderBeginTag("div");

output.RenderBeginTag(HtmlTextWriterTag.Table);

output.RenderBeginTag("table");

output.RenderBeginTag(HtmlTextWriterTag.Input);

output.RenderBeginTag("input");

u 关于RenderBeginTag和枚举HtmlTextWriterTag 的功能就不再多说了。只说一下这个方法输出标记对应控件的位置,看一下这个控件标记:

  1. <divid="div1"align="center"style="border-color:Blue"></div>

RenderBeginTag

不是为控件生成属性和样式属性标记,而是生成控件标记,即上面例子中的绿色文本部分<div></div>

在实际开发中建议尽量使用HtmlTextWriterAttributeHtmlTextWriterStyleHtmlTextWriterTag枚举生成控件以及其属性标记,使用这些枚举输出最大的好处是我们不用关心浏览器的兼容性,让它在Render时自行处理,否则我们必须得保证当前浏览器要支持此标记。例如:

output.RenderBeginTag(HtmlTextWriterTag.Div);

u 此写法要比如下写法好:

  1. output.RenderBeginTag("div");

这些枚举中不包含的

HTML标记时,可直接使用标记字符串。

相信读者通过以上这么多示例应该对HtmlTextWriter类有了系统的认识。另外,在HtmlTextWriter类中还包含了很多常用的方法和属性,感兴趣的读者可以自己去研究,并在实践中应用它们。

3.3.2 直接输出HTML标签

先看例子,也以输出一个超链接控件为例:

/// <summary>

/// 获得本书更多内容,请看:

/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx

/// </summary>

protected override void RenderContents(HtmlTextWriter output)

{

output.Write("<a href='http://www.csdn.net' target='blank' style='color: Blue;cursor:Hand;'>");

output.Write(this.Text);

output.Write("</a>");

}

u HtmlTextWriter对象还有个非常重要的方法Write,可以用这个方法直接输出HTML标记,如上面的代码所示。如果方法中的参数是一个有效的HTML标记或一个HTML控件标记串,则它能够自动识别并输出该标记对应的浏览结果到浏览器。反之,如果该方法接收的参数不是有效的HTML标记,则直接输出参数,如:

  1. output.Write(this.Text);

就是直接将属性

Text的值输出。

当要连续输出多个HTML标记时,调用多个Write方法把标记直接输出到输出流中要比先组装好字符串再一次性输出到输出流中效率要高,即:

output.Write("<div id='div1'>");

output.Write("<table><tr><td>");

output.Write("性能比较”);

output.Write("</td></tr></table>");

output.Write("</div");

u 运行效率要高于:

string str = "<div id=’div1’>";

str += "<table><tr><td>";

str += "性能比较";

str += "</td></tr></table>”;

str += "</div>";

output.Write(str);

u 另外,强烈建议不要把3.3.1节和3.3.2节介绍的方式混用,这样做除了代码比较混乱,不便于阅读外,还有一个重要的原因,笔者在项目开发中就遇到过这种情况。先看这个例子:

  1. ///<summary>
  2. ///获得本书更多内容,请看:
  3. ///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
  4. ///</summary>
  5. protectedoverridevoidRenderContents(HtmlTextWriteroutput)
  6. {
  7. output.AddAttribute(HtmlTextWriterAttribute.Cellpadding,"0");
  8. output.AddAttribute(HtmlTextWriterAttribute.Cellspacing,"0");
  9. output.AddAttribute(HtmlTextWriterAttribute.Border,"0");
  10. output.RenderBeginTag(HtmlTextWriterTag.Table);
  11. output.Write("<TR><TD>我是单元格内容</TD></TR>");
  12. output.Write("</TABLE");
  13. }

以上代码仅输出一个表格

包含一行一列且单元格内容为我是单元格内容。从结构上看各个标签的起始和结尾标记都比较匹配事实上呈现到浏览器中的标记为

<shape id="_x0000_i1027" style="WIDTH: 183pt; HEIGHT: 32.25pt" type="#_x0000_t75"><imagedata src="file:///D:%5CDOCUME~1%5CZHENGJ~1%5CLOCALS~1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image005.png" o:title=""><font color="#000000" size="2"></font></imagedata></shape>

最后一行如上代码所示,多一个</table>标签,这是由于HtmlTextWriter的方法输出控件标记时比较智能,output.RenderEndTag可以省略,运行环境在运行时会自动检测到默认的尾签并自动追加。以上代码比较简单,事实上可以省略所有的RenderEndTag标记。

以上例子出现输出错误标记的原因是,运行环境在生成控件时无法检测到我们已经用output.Write方法输出了一个</table>结束标记。

3.3.3 使用服务器控件的RenderControl方法

再介绍一种控件输出方法,直接用服务器控件的RenderControl方法进行把控件Render到输出流中。请看代码:

  1. ///<summary>
  2. ///获得本书更多内容,请看:
  3. ///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
  4. ///</summary>
  5. protectedoverridevoidRenderContents(HtmlTextWriteroutput)
  6. {
  7. //方式
  8. HtmlGenericControlA=newHtmlGenericControl("A");
  9. A.Attributes.Add("href","http://blog.csdn.net/ChengKing");
  10. A.Attributes.Add("target","blank");
  11. A.Style.Add(HtmlTextWriterStyle.Color,"Blue");
  12. A.S
    分享到:
    评论

相关推荐

Global site tag (gtag.js) - Google Analytics