中国人民大学金融硕士:从零开始开发服务器控件
来源:百度文库 编辑:中财网 时间:2024/05/24 00:50:06
第3章 从零开始开发服务器控件
本章内容
3.1 选择基类
3.2 控件呈现顺序
3.3 Render呈现控件的几种方式
3.4 AddAttributesToRender方法
3.5 CreateChildControls方法
3.6 INamingContainer接口
3.7 实现复合控件
3.8 常用开发技巧
3.1 选择基类
在开发一个控件之前要先选择控件开发要继承的基类,这些基类封装了控件最基本的功能,可以提高代码重用性,并且每个基类提供的功能不同,在第1章中已经列出了许多常用基类,如果您还不大清楚,请看一下第1章。
这里仅谈一谈一般开发基本控件所选择基类的方式。
Control
控件开发基类,所有控件都直接或间接继承该类。提供了各类控件通用属性和方法,如唯一标志ID属性、可见性Visible等。
该类仅具有控件最基本的属性,扩展灵活性最强。
WebControl
WebControl除了继承了Control的所有属性,还增加了布局、可访问性、外观样式等特性;另外,对行为也扩充了好多属性。
Control和WebControl都用于开发简单控件(即单个控件或非组件控件)。一般在选择控件时,如果要开发的控件对外观布局和样式等控件特性要求比较高,则可以选择继承WebControl要方便得多;反之,选用Control实现即可。如果一定要选用Control实现WebControl的特性也是可以的,但要自己增加所需的属性,如布局属性width和height,实现起来会较麻烦。
一般在基于Web的系统中用得最多,扩展灵活性也很强。
CompositeControl
此类为ASP.NET 2.0版本时已经支持的一个控件基类。如果把现有控件聚合起来创建一个组合控件时,可以继承此类,此类默认实现了INamingContainer接口,并且对设计模式表现有较好的支持。后面会详细介绍其创建方法。一般用于将具有一定功能的多个控件集成为一个控件的情况。
继承现有控件
把具有一定功能的成型控件,如Label,Button,甚至GridView等控件,作为新控件的基类,并在此基础上扩展或改变(通过override重载其方法实现)其功能,满足业务需要。
一般情况下开发一个基于Web平台的控件,比较常用的方法是从WebControl继承;本章主要讲开发一个控件的过程。就以继承WebControl为例来展开讲解。
只要是Web控件,不管是ASP.NET控件还是第三方厂商控件,最终被解析到客户端的都是标准的HTML标记。也可以这么说,做一个控件的过程就是根据控件使用者设置控件的属性(简单值或复杂数据源集合等)进行组织HTML并输出的过程。控件无非就是把一些常用的功能抽象成一个通用的控件,提高重用性,节省开发时间,这样要比之前开发人员对每个页面用纯HTML开发要好多了。
控件开发可以理解为组织HTML的过程。当然ASP.NET控件开发技术提供了一些规则,用多种方式有效地组织输出这些HTML标记,对样式、资源文件封装等也提供了一些帮助类和功能支持,下面我们就一起来看一下组织HTML标记的方式。
3.2 控件呈现顺序
控件生命周期的Render阶段,主要将控件标记和字符文本输出到服务器控件输出流中。在这个阶段可以直接写HTML标记,也可以调用每个控件都有的RenderControl方法到输出流。在WebControl基类中,以Render开头的呈现方法有如下几个:
RenderControl(HtmlTextWriter writer)
Render(HtmlTextWriter writer)
RenderBeginTag(HtmlTextWriter writer)
RenderContents(HtmlTextWriter output)
RenderEndTag(HtmlTextWriter writer)
以上几个Render方法并不是毫无联系的,它们的执行顺序是从上往下,并且有嵌套的调用关系。其中在RenderControl方法内部会调用Render方法,在Render方法内部会依次调用RenderBeginTag, RenderContents和RenderEndTag。
其中RenderControl和Render是Control基类中的方法,因为WebControl本身也是继承Control的。一般在开发基本控件时,我们只需重写RenderContents方法即可,在此方法中可以把控件HTML文本标记和其他内容写到输出流中。
另外,还有两个可以重载的方法 RenderBeginTag和RenderEndTag。这两个方法执行时刻点是分别在Render控件内容之前和之后。可以重写这两个方法自己定义控件的起始和结束标记。默认情况下控件是以作为起始和结束标记的,图3-1是没有重写标记的一个控件的默认显示。
(点击查看大图)图3-1 控件默认标记是
下面以一个例子来演示使用上面几个Render方法。新建一个RenderOrderControl.cs Web控件类,重载以下几个方法,并填充相应语句。代码如下所示:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// ///
/// Render方法执行顺序: 3
///
public override void RenderBeginTag(HtmlTextWriter writer)
{
//base.RenderBeginTag(writer);
writer.AddAttribute( HtmlTextWriterAttribute.Id, this.ID);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
///
/// Render方法执行顺序: 4
///
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
}
///
/// Render方法执行顺序: 5
///
public override void RenderEndTag(HtmlTextWriter writer)
{
//base.RenderEndTag(writer);
writer.RenderEndTag();
}
上面代码仅呈现出控件Text属性文本。另外,重写了控件起始和结尾标签。呈现到浏览器中的控件如图3-2所示。
(点击查看大图)图3-2 控件重写标记为
另外,读者可能注意到在RenderBeginTag和RenderEndTag方法中有:
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类输出
先看一个例子,其功能是输出一个超链接控件:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
//方式
output.AddAttribute(HtmlTextWriterAttribute.Href,"http://www.cnblogs.com/");
output.AddAttribute(HtmlTextWriterAttribute.Target, "blank");
output.AddStyleAttribute(HtmlTextWriterStyle.Color, "Blue");
output.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "Hand");
output.RenderBeginTag(HtmlTextWriterTag.A);
output.Write(this.Text);
output.RenderEndTag(); output.WriteBreak();
}
RenderContents方法的参数类型为HtmlTextWriter,是具有呈现标记和其他HTML标记(包括HTML变量)的方法的实用工具类。该类能将控件的字符和文本标记等写入到服务器控件输出流中。并且此类在运行期间会自动生成实例。
Output.AddAttribute方法生成控件的属性,它有许多重载方法,可以直接以字符串形式把属性名称和属性值写入到输出流,也可以使用HtmlTextWriterAttribute枚举,帮助输入控件属性,如下都是使用AddAttribute方法的一些例子:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
output.AddAttribute(HtmlTextWriterAttribute.Accesskey, "n");
output.AddAttribute("Accesskey", "n");output.AddAttribute(HtmlTextWriterAttribute.Bgcolor, "#6699ff");
output.AddAttribute("bgcolor", "#6699ff");output.AddAttribute(HtmlTextWriterAttribute.Checked, "true");
output.AddAttribute("checked", "true");output.AddAttribute(HtmlTextWriterAttribute.Class, "TextBoxStyleName");
output.AddAttribute("class", "TextBoxStyleName");output.AddAttribute(HtmlTextWriterAttribute.Onclick, "alert('Hello');");
output.AddAttribute("onclick", "alert('Hello');");output.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "true");
output.AddAttribute("readonly", "true");output.AddAttribute(HtmlTextWriterAttribute.Tabindex, "5");
output.AddAttribute("tabindex", "5");
不用多说,仅通过这些例子读者就能够理解AddAttribute方法和HtmlTextWriterAttribute枚举的用途了。其中AddAttribute方法除了能够为控件增加一般属性外,还能够增加客户端事件属性,如上面例子中的"onclick"属性。
HtmlTextWriterAttribute枚举包含了几乎所有控件的属性标记,同时也要求使用者了解不同的控件具有一些不同的属性标记,在知道要添加的控件具有某个枚举值的情况下才为其增加某个属性标记,避免把控件弄成"驴头对马身"情况。
Output.AddStyleAttribute方法生成控件的样式属性,像s="width:100%;" 中的width就是样式属性标记。同样使用HtmlTextWriterStyle枚举也可以帮助快速输入样式属性标记。通过如下示例了解一下它的功能:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "#6699ff");
output.AddStyleAttribute("background-color", "#6699ff");output.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "Hand");
output.AddStyleAttribute("cursor", "Hand");output.AddStyleAttribute(HtmlTextWriterStyle.Display, "block");
output.AddStyleAttribute("display", "block");output.AddStyleAttribute(HtmlTextWriterStyle.Left, "20px");
output.AddStyleAttribute("left", "20px");output.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "auto");
output.AddStyleAttribute("overflow", "auto");output.AddStyleAttribute(HtmlTextWriterStyle.Visibility, "true");
output.AddStyleAttribute("visibility", "true");output.AddStyleAttribute(HtmlTextWriterStyle.ZIndex, "100");
output.AddStyleAttribute("z-index", "100");
本例中AddStyleAttribute和HtmlTextWriterStyle与前面的AddAttribute和HtmlText WriterAttribute用法一样。它们的区别也可以用一个例子来演示:
其中蓝色属性align="center" 就是用AddAttribute方法输出的位置;粉红色样式属性s="border-color:Blue" 就是使用AddStyleAttribute方法输出的位置,样式属性嵌套在复合属性style中。一般属性(AddAttribute方法增加的属性)与样式属性(AddStyleAttribute方法增加的属性)有些具有相同功能的标记,比如,既可以使用一般属性也可以使用样式属性给控件设置背景色,但它们作用于控件的优先级是不一样的。
还有一对很重要且常用的方法RenderBeginTag和枚举HtmlTextWriterTag。下例演示了它们的功能:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
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");
关于RenderBeginTag和枚举HtmlTextWriterTag 的功能就不再多说了。只说一下这个方法输出标记对应控件的位置,看一下这个控件标记:
RenderBeginTag不是为控件生成属性和样式属性标记,而是生成控件标记,即上面例子中的绿色文本部分
在实际开发中建议尽量使用HtmlTextWriterAttribute,HtmlTextWriterStyle和HtmlTextWriterTag枚举生成控件以及其属性标记,使用这些枚举输出最大的好处是我们不用关心浏览器的兼容性,让它在Render时自行处理,否则我们必须得保证当前浏览器要支持此标记。例如:
output.RenderBeginTag(HtmlTextWriterTag.Div);
此写法要比如下写法好:
output.RenderBeginTag("div");
这些枚举中不包含的HTML标记时,可直接使用标记字符串。
相信读者通过以上这么多示例应该对HtmlTextWriter类有了系统的认识。另外,在HtmlTextWriter类中还包含了很多常用的方法和属性,感兴趣的读者可以自己去研究,并在实践中应用它们。
3.3.2 直接输出HTML标签
先看例子,也以输出一个超链接控件为例:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
output.Write("target='blank' s='color: Blue;cursor:Hand;'>");
output.Write(this.Text);
output.Write("");
}
HtmlTextWriter对象还有个非常重要的方法Write,可以用这个方法直接输出HTML标记,如上面的代码所示。如果方法中的参数是一个有效的HTML标记或一个HTML控件标记串,则它能够自动识别并输出该标记对应的浏览结果到浏览器。反之,如果该方法接收的参数不是有效的HTML标记,则直接输出参数,如:
output.Write(this.Text);
就是直接将属性Text的值输出。
当要连续输出多个HTML标记时,调用多个Write方法把标记直接输出到输出流中要比先组装好字符串再一次性输出到输出流中效率要高,即:
output.Write("
string str = "
output.Write(str);
另外,强烈建议不要把3.3.1节和3.3.2节介绍的方式混用,这样做除了代码比较混乱,不便于阅读外,还有一个重要的原因,笔者在项目开发中就遇到过这种情况。先看这个例子:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
output.AddAttribute(HtmlTextWriterAttribute.Border, "0");
output.RenderBeginTag(HtmlTextWriterTag.Table);
output.Write("我是单元格内容 ");
output.Write("}
以上代码仅输出一个表格,包含一行一列,且单元格内容为:我是单元格内容。从结构上看,各个标签的起始和结尾标记都比较匹配。事实上呈现到浏览器中的标记为:
最后一行如上代码所示,多一个标签,这是由于HtmlTextWriter的方法输出控件标记时比较智能,output.RenderEndTag可以省略,运行环境在运行时会自动检测到默认的尾签并自动追加。以上代码比较简单,事实上可以省略所有的RenderEndTag标记。
以上例子出现输出错误标记的原因是,运行环境在生成控件时无法检测到我们已经用output.Write方法输出了一个结束标记。
3.3.3 使用服务器控件的RenderControl方法
再介绍一种控件输出方法,直接用服务器控件的RenderControl方法进行把控件Render到输出流中。请看代码:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
//方式
HtmlGenericControl A = new HtmlGenericControl("A");
A.Attributes.Add("href", "http://blog.csdn.net/ChengKing");
A.Attributes.Add("target", "blank");
A.Style.Add(HtmlTextWriterStyle.Color, "Blue");
A.Style.Add(HtmlTextWriterStyle.Cursor, "Hand");
A.InnerText = this.Text;
A.RenderControl(output);
}
该示例也是生成一个超链接标签控件,大部分ASP.NET现有控件都会有控件对应的类,如Button,Label控件等对应的类分别为Button和Label。但HTML标签非常灵活且标记比较多,.NET framework没有一一提供专门的类,那些没有专门提供类的标记是用类HtmlGenericControl类取代,使用时把要生成控件的HTML标签作为参数传入该类的构造方法即可。如上例中的:new HtmlGenericControl("A");然后为控件增加一些属性和样式属性。再使用控件的RenderControl()方法呈现到控件输出流对象中。使用这种输出方式其效率要比直接输出HTML标记要低些,但是在很多场景下,比如创建复合控件时不得不用此方法。
采用3.3.1节和3.3.2节方式的优点是执行速度非常快。因为它直接输出的是HTML标记,省去了从服务器控件解析成HTML标记的时间;而采用3.3.3节的方式在控件解析时把服务端控件解析成HTML标记是要花些时间的,相对来说效率会低一点。
采用3.3.1节和3.3.2节方式的缺点是,代码已经写死,以至于它不能自动识别浏览器,这样就不能根据浏览器类型生成对应的能够被各个浏览器识别的代码,那么做成的控件有可能在有些浏览器上不能够正常呈现或功能受限等。反之,使用3.3.3节方式输出即可以实现大部分跨浏览器的不同代码。如果读者对HTML标记掌握得不是非常熟练的话,笔者不建议使用3.3.2节方式输出控件内容标记。另外,使用Write方法最致命的缺点是服务器无法识别它(它不包含于服务器的控件集合中,对于保存页面状态的视图状态ViewState来说,里面也不会保存这些控件的信息),即使设置了name属性。也就是说它一般用于直接输出文本,或者输出简单HTML标签,前提是这些标签不处理服务端事件或处理服务端回发数据。
以上介绍了三种输出控件标记的方法,使用的例子很简单,但能够说明开发所有控件的方式和注意事项,比较容易懂。同时也分析了各种方式的优缺点,这些优缺点并不是绝对的,要根据实际场景选用合适的方法。事实上我们在开发控件的过程中,以上几种输出方式都用到了。
3.4 AddAttributesToRender方法
除了上面讲到的在Render方法中输出控件内容之外,使用AddAttributesToRender方法也是一个比较好的输出方式。使用AddAttributesToRender方式一般在创建原生控件(单个元素)时用的较多,且此方法一般与方法RenderContents方法一起使用。
此重载方法可以为当前自定义控件容器标记增加属性,即对控件呈现HTML标记的最外层一级增加属性。
通过一个简单示例来讲解一下它的用法,其代码如下:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// public class AddAttributesToRenderControl : WebControl
{ ///
/// 重载TagKey属性, 使用替换掉默认的
,这样就与RenderContents输出控件内容匹配为一个完整的表格。如果不重载TagKey,它也会自动生成一个基本的容器标记。
AddAttributesRender重载方法主要是为重载的TagKey增加一些属性,在实际应用时可以在本方法中任意设置TagKey支持的属性。在这里设置了几个标记支持的属性。
本章内容
3.1 选择基类
3.2 控件呈现顺序
3.3 Render呈现控件的几种方式
3.4 AddAttributesToRender方法
3.5 CreateChildControls方法
3.6 INamingContainer接口
3.7 实现复合控件
3.8 常用开发技巧
3.1 选择基类
在开发一个控件之前要先选择控件开发要继承的基类,这些基类封装了控件最基本的功能,可以提高代码重用性,并且每个基类提供的功能不同,在第1章中已经列出了许多常用基类,如果您还不大清楚,请看一下第1章。
这里仅谈一谈一般开发基本控件所选择基类的方式。
Control
控件开发基类,所有控件都直接或间接继承该类。提供了各类控件通用属性和方法,如唯一标志ID属性、可见性Visible等。
该类仅具有控件最基本的属性,扩展灵活性最强。
WebControl
WebControl除了继承了Control的所有属性,还增加了布局、可访问性、外观样式等特性;另外,对行为也扩充了好多属性。
Control和WebControl都用于开发简单控件(即单个控件或非组件控件)。一般在选择控件时,如果要开发的控件对外观布局和样式等控件特性要求比较高,则可以选择继承WebControl要方便得多;反之,选用Control实现即可。如果一定要选用Control实现WebControl的特性也是可以的,但要自己增加所需的属性,如布局属性width和height,实现起来会较麻烦。
一般在基于Web的系统中用得最多,扩展灵活性也很强。
CompositeControl
此类为ASP.NET 2.0版本时已经支持的一个控件基类。如果把现有控件聚合起来创建一个组合控件时,可以继承此类,此类默认实现了INamingContainer接口,并且对设计模式表现有较好的支持。后面会详细介绍其创建方法。一般用于将具有一定功能的多个控件集成为一个控件的情况。
继承现有控件
把具有一定功能的成型控件,如Label,Button,甚至GridView等控件,作为新控件的基类,并在此基础上扩展或改变(通过override重载其方法实现)其功能,满足业务需要。
一般情况下开发一个基于Web平台的控件,比较常用的方法是从WebControl继承;本章主要讲开发一个控件的过程。就以继承WebControl为例来展开讲解。
只要是Web控件,不管是ASP.NET控件还是第三方厂商控件,最终被解析到客户端的都是标准的HTML标记。也可以这么说,做一个控件的过程就是根据控件使用者设置控件的属性(简单值或复杂数据源集合等)进行组织HTML并输出的过程。控件无非就是把一些常用的功能抽象成一个通用的控件,提高重用性,节省开发时间,这样要比之前开发人员对每个页面用纯HTML开发要好多了。
控件开发可以理解为组织HTML的过程。当然ASP.NET控件开发技术提供了一些规则,用多种方式有效地组织输出这些HTML标记,对样式、资源文件封装等也提供了一些帮助类和功能支持,下面我们就一起来看一下组织HTML标记的方式。
3.2 控件呈现顺序
控件生命周期的Render阶段,主要将控件标记和字符文本输出到服务器控件输出流中。在这个阶段可以直接写HTML标记,也可以调用每个控件都有的RenderControl方法到输出流。在WebControl基类中,以Render开头的呈现方法有如下几个:
RenderControl(HtmlTextWriter writer)
Render(HtmlTextWriter writer)
RenderBeginTag(HtmlTextWriter writer)
RenderContents(HtmlTextWriter output)
RenderEndTag(HtmlTextWriter writer)
以上几个Render方法并不是毫无联系的,它们的执行顺序是从上往下,并且有嵌套的调用关系。其中在RenderControl方法内部会调用Render方法,在Render方法内部会依次调用RenderBeginTag, RenderContents和RenderEndTag。
其中RenderControl和Render是Control基类中的方法,因为WebControl本身也是继承Control的。一般在开发基本控件时,我们只需重写RenderContents方法即可,在此方法中可以把控件HTML文本标记和其他内容写到输出流中。
另外,还有两个可以重载的方法 RenderBeginTag和RenderEndTag。这两个方法执行时刻点是分别在Render控件内容之前和之后。可以重写这两个方法自己定义控件的起始和结束标记。默认情况下控件是以作为起始和结束标记的,图3-1是没有重写标记的一个控件的默认显示。
(点击查看大图)图3-1 控件默认标记是
下面以一个例子来演示使用上面几个Render方法。新建一个RenderOrderControl.cs Web控件类,重载以下几个方法,并填充相应语句。代码如下所示:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
/// Render方法执行顺序: 3
///
public override void RenderBeginTag(HtmlTextWriter writer)
{
//base.RenderBeginTag(writer);
writer.AddAttribute( HtmlTextWriterAttribute.Id, this.ID);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
///
/// Render方法执行顺序: 4
///
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
}
///
/// Render方法执行顺序: 5
///
public override void RenderEndTag(HtmlTextWriter writer)
{
//base.RenderEndTag(writer);
writer.RenderEndTag();
}
上面代码仅呈现出控件Text属性文本。另外,重写了控件起始和结尾标签。呈现到浏览器中的控件如图3-2所示。
(点击查看大图)图3-2 控件重写标记为
另外,读者可能注意到在RenderBeginTag和RenderEndTag方法中有:
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类输出
先看一个例子,其功能是输出一个超链接控件:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
//方式
output.AddAttribute(HtmlTextWriterAttribute.Href,"http://www.cnblogs.com/");
output.AddAttribute(HtmlTextWriterAttribute.Target, "blank");
output.AddStyleAttribute(HtmlTextWriterStyle.Color, "Blue");
output.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "Hand");
output.RenderBeginTag(HtmlTextWriterTag.A);
output.Write(this.Text);
output.RenderEndTag(); output.WriteBreak();
}
RenderContents方法的参数类型为HtmlTextWriter,是具有呈现标记和其他HTML标记(包括HTML变量)的方法的实用工具类。该类能将控件的字符和文本标记等写入到服务器控件输出流中。并且此类在运行期间会自动生成实例。
Output.AddAttribute方法生成控件的属性,它有许多重载方法,可以直接以字符串形式把属性名称和属性值写入到输出流,也可以使用HtmlTextWriterAttribute枚举,帮助输入控件属性,如下都是使用AddAttribute方法的一些例子:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
output.AddAttribute(HtmlTextWriterAttribute.Accesskey, "n");
output.AddAttribute("Accesskey", "n");output.AddAttribute(HtmlTextWriterAttribute.Bgcolor, "#6699ff");
output.AddAttribute("bgcolor", "#6699ff");output.AddAttribute(HtmlTextWriterAttribute.Checked, "true");
output.AddAttribute("checked", "true");output.AddAttribute(HtmlTextWriterAttribute.Class, "TextBoxStyleName");
output.AddAttribute("class", "TextBoxStyleName");output.AddAttribute(HtmlTextWriterAttribute.Onclick, "alert('Hello');");
output.AddAttribute("onclick", "alert('Hello');");output.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "true");
output.AddAttribute("readonly", "true");output.AddAttribute(HtmlTextWriterAttribute.Tabindex, "5");
output.AddAttribute("tabindex", "5");
不用多说,仅通过这些例子读者就能够理解AddAttribute方法和HtmlTextWriterAttribute枚举的用途了。其中AddAttribute方法除了能够为控件增加一般属性外,还能够增加客户端事件属性,如上面例子中的"onclick"属性。
HtmlTextWriterAttribute枚举包含了几乎所有控件的属性标记,同时也要求使用者了解不同的控件具有一些不同的属性标记,在知道要添加的控件具有某个枚举值的情况下才为其增加某个属性标记,避免把控件弄成"驴头对马身"情况。
Output.AddStyleAttribute方法生成控件的样式属性,像s="width:100%;" 中的width就是样式属性标记。同样使用HtmlTextWriterStyle枚举也可以帮助快速输入样式属性标记。通过如下示例了解一下它的功能:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "#6699ff");
output.AddStyleAttribute("background-color", "#6699ff");output.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "Hand");
output.AddStyleAttribute("cursor", "Hand");output.AddStyleAttribute(HtmlTextWriterStyle.Display, "block");
output.AddStyleAttribute("display", "block");output.AddStyleAttribute(HtmlTextWriterStyle.Left, "20px");
output.AddStyleAttribute("left", "20px");output.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "auto");
output.AddStyleAttribute("overflow", "auto");output.AddStyleAttribute(HtmlTextWriterStyle.Visibility, "true");
output.AddStyleAttribute("visibility", "true");output.AddStyleAttribute(HtmlTextWriterStyle.ZIndex, "100");
output.AddStyleAttribute("z-index", "100");
本例中AddStyleAttribute和HtmlTextWriterStyle与前面的AddAttribute和HtmlText WriterAttribute用法一样。它们的区别也可以用一个例子来演示:
其中蓝色属性align="center" 就是用AddAttribute方法输出的位置;粉红色样式属性s="border-color:Blue" 就是使用AddStyleAttribute方法输出的位置,样式属性嵌套在复合属性style中。一般属性(AddAttribute方法增加的属性)与样式属性(AddStyleAttribute方法增加的属性)有些具有相同功能的标记,比如,既可以使用一般属性也可以使用样式属性给控件设置背景色,但它们作用于控件的优先级是不一样的。
还有一对很重要且常用的方法RenderBeginTag和枚举HtmlTextWriterTag。下例演示了它们的功能:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
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");
关于RenderBeginTag和枚举HtmlTextWriterTag 的功能就不再多说了。只说一下这个方法输出标记对应控件的位置,看一下这个控件标记:
RenderBeginTag不是为控件生成属性和样式属性标记,而是生成控件标记,即上面例子中的绿色文本部分
和
。在实际开发中建议尽量使用HtmlTextWriterAttribute,HtmlTextWriterStyle和HtmlTextWriterTag枚举生成控件以及其属性标记,使用这些枚举输出最大的好处是我们不用关心浏览器的兼容性,让它在Render时自行处理,否则我们必须得保证当前浏览器要支持此标记。例如:
output.RenderBeginTag(HtmlTextWriterTag.Div);
此写法要比如下写法好:
output.RenderBeginTag("div");
这些枚举中不包含的HTML标记时,可直接使用标记字符串。
相信读者通过以上这么多示例应该对HtmlTextWriter类有了系统的认识。另外,在HtmlTextWriter类中还包含了很多常用的方法和属性,感兴趣的读者可以自己去研究,并在实践中应用它们。
3.3.2 直接输出HTML标签
先看例子,也以输出一个超链接控件为例:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
output.Write("target='blank' s='color: Blue;cursor:Hand;'>");
output.Write(this.Text);
output.Write("");
}
HtmlTextWriter对象还有个非常重要的方法Write,可以用这个方法直接输出HTML标记,如上面的代码所示。如果方法中的参数是一个有效的HTML标记或一个HTML控件标记串,则它能够自动识别并输出该标记对应的浏览结果到浏览器。反之,如果该方法接收的参数不是有效的HTML标记,则直接输出参数,如:
output.Write(this.Text);
就是直接将属性Text的值输出。
当要连续输出多个HTML标记时,调用多个Write方法把标记直接输出到输出流中要比先组装好字符串再一次性输出到输出流中效率要高,即:
output.Write("
");
output.Write("
");
output.Write("
运行效率要高于:output.Write("
"); output.Write("性能比较"); output.Write(" |
output.Write("
string str = "
";
str += "
";
str += "
";str += "
"; str += "性能比较"; str += " |
str += "
output.Write(str);
另外,强烈建议不要把3.3.1节和3.3.2节介绍的方式混用,这样做除了代码比较混乱,不便于阅读外,还有一个重要的原因,笔者在项目开发中就遇到过这种情况。先看这个例子:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
output.AddAttribute(HtmlTextWriterAttribute.Border, "0");
output.RenderBeginTag(HtmlTextWriterTag.Table);
output.Write("
output.Write("}
以上代码仅输出一个表格,包含一行一列,且单元格内容为:我是单元格内容。从结构上看,各个标签的起始和结尾标记都比较匹配。事实上呈现到浏览器中的标记为:
最后一行如上代码所示,多一个标签,这是由于HtmlTextWriter的方法输出控件标记时比较智能,output.RenderEndTag可以省略,运行环境在运行时会自动检测到默认的尾签并自动追加。以上代码比较简单,事实上可以省略所有的RenderEndTag标记。
以上例子出现输出错误标记的原因是,运行环境在生成控件时无法检测到我们已经用output.Write方法输出了一个结束标记。
3.3.3 使用服务器控件的RenderControl方法
再介绍一种控件输出方法,直接用服务器控件的RenderControl方法进行把控件Render到输出流中。请看代码:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
protected override void RenderContents(HtmlTextWriter output)
{
//方式
HtmlGenericControl A = new HtmlGenericControl("A");
A.Attributes.Add("href", "http://blog.csdn.net/ChengKing");
A.Attributes.Add("target", "blank");
A.Style.Add(HtmlTextWriterStyle.Color, "Blue");
A.Style.Add(HtmlTextWriterStyle.Cursor, "Hand");
A.InnerText = this.Text;
A.RenderControl(output);
}
该示例也是生成一个超链接标签控件,大部分ASP.NET现有控件都会有控件对应的类,如Button,Label控件等对应的类分别为Button和Label。但HTML标签非常灵活且标记比较多,.NET framework没有一一提供专门的类,那些没有专门提供类的标记是用类HtmlGenericControl类取代,使用时把要生成控件的HTML标签作为参数传入该类的构造方法即可。如上例中的:new HtmlGenericControl("A");然后为控件增加一些属性和样式属性。再使用控件的RenderControl()方法呈现到控件输出流对象中。使用这种输出方式其效率要比直接输出HTML标记要低些,但是在很多场景下,比如创建复合控件时不得不用此方法。
采用3.3.1节和3.3.2节方式的优点是执行速度非常快。因为它直接输出的是HTML标记,省去了从服务器控件解析成HTML标记的时间;而采用3.3.3节的方式在控件解析时把服务端控件解析成HTML标记是要花些时间的,相对来说效率会低一点。
采用3.3.1节和3.3.2节方式的缺点是,代码已经写死,以至于它不能自动识别浏览器,这样就不能根据浏览器类型生成对应的能够被各个浏览器识别的代码,那么做成的控件有可能在有些浏览器上不能够正常呈现或功能受限等。反之,使用3.3.3节方式输出即可以实现大部分跨浏览器的不同代码。如果读者对HTML标记掌握得不是非常熟练的话,笔者不建议使用3.3.2节方式输出控件内容标记。另外,使用Write方法最致命的缺点是服务器无法识别它(它不包含于服务器的控件集合中,对于保存页面状态的视图状态ViewState来说,里面也不会保存这些控件的信息),即使设置了name属性。也就是说它一般用于直接输出文本,或者输出简单HTML标签,前提是这些标签不处理服务端事件或处理服务端回发数据。
以上介绍了三种输出控件标记的方法,使用的例子很简单,但能够说明开发所有控件的方式和注意事项,比较容易懂。同时也分析了各种方式的优缺点,这些优缺点并不是绝对的,要根据实际场景选用合适的方法。事实上我们在开发控件的过程中,以上几种输出方式都用到了。
3.4 AddAttributesToRender方法
除了上面讲到的在Render方法中输出控件内容之外,使用AddAttributesToRender方法也是一个比较好的输出方式。使用AddAttributesToRender方式一般在创建原生控件(单个元素)时用的较多,且此方法一般与方法RenderContents方法一起使用。
此重载方法可以为当前自定义控件容器标记增加属性,即对控件呈现HTML标记的最外层一级增加属性。
通过一个简单示例来讲解一下它的用法,其代码如下:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
{ ///
/// 重载TagKey属性, 使用
AddAttributesRender重载方法主要是为重载的TagKey增加一些属性,在实际应用时可以在本方法中任意设置TagKey支持的属性。在这里设置了几个
,每个 | 中输出一个友情链接。 采用AddAttributesRender和RenderContents输出控件还有个好处,就是在RenderContents中只关心输出的内容,不用关心控件容器标记的输出。比如当要循环输出一些内容标记(如 |
模拟数据 | 模拟数据 |
}
else
{
//访问数据库,取得真实数据,并输出列表
}
}
不管是设计模式还是运行模式,Render方法都会执行。使用条件语句来进行区分,在设计模式下,仅输出两列模拟数据,类型与我们在IDE设计器中使用GridView时看到的模拟数据一样;如果是在运行模式,则会在浏览器中看到从数据库中读取的真实数据。
3.8.2 屏蔽基类控件中的属性
一般我们开发的控件,大多数都会继承基类,比如基类Control,WebControl或Button, GridView等现有控件,只要是继承肯定会遇到这样的场景:继承后的控件会屏蔽某个功能,即我们需要屏蔽基类中的某个属性和方法。在3.2节中详细讲解了处理继承方法的5种方式,这里再增加一种屏蔽基类功能的一种场景,只要对某个属性(或方法)增加以下几个特性即可:
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
[Bindable(false),Browsable(false),EditorBrowsable(EditorBrowsableState.Never)]
public override Unit Height
{
get
{
return new Unit();
}
}
Bindable(false)属性指定此属性不需要绑定;Browsable(false)指定此属性不在属性窗口显示;EditorBrowsable(EditorBrowsableState.Never)指定此属性不在编辑器中看到,即在后台*.cs文件中不会在智能提示中出现此属性。
比如在Button控件中有Height属性,并且MyButton控件继承于Button,如果在MyButton中用以上方式屏蔽了Height属性,则在MyButton控件中就没有Height功能;但不影响单独使用Button时的Height功能。
///
/// 获得本书更多内容,请看:
///http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
///
private Unit unitTextBoxWidth = Unit.Empty;
[Category("LabelTextBox")]
[Description("文本框宽度")]
public Unit TextBoxWidth
{
get
{
this.EnsureChildControls();
return this.tb.Width;
}
set
{
this.EnsureChildControls();
this.tb.Width = value;
}
}
权限管理控件开发
求<asp.net服务器控件开发技术与实例>光盘源码
求ASP.NET服务器控件开发技术与实例一书源码 topweb520@126.com 谢谢了
从零开始
从零开始
html服务器控件
开发服务器的项目
.net Table Web服务器控件
如何开发IE的插件(ActiveX控件)
现在开发注册表控件有没有价值
怎样开发电子邮件接收服务器
web开发中的ftp服务器?
ASP.NET的服务器控件怎么用?
服务器控件中文本框的Bug
VB怎样用winsock控件连接QQ服务器?
自由报表OCX控件该从什么地方入手来开发
delphi开发中,控件AMCLOCK的使用问题,急需帮忙
ATL开发ActiveX控件问题?急急急急急急急!!!!!
控件产品对于软件开发 有多大的作用啊?
如何使用vb开发的ActiveX控件调用Java Script
邮件服务器开发需要解决的问题
.net中客户端控件和服务器控件的用法区别,如input和TextBox
英语从零开始
求助:从零开始