创造的魅力——定制控件
从上面对用户控件的总体介绍中我们可以看出,用户控件只是实现了对已有控件的组合,从而形成新的控件。喜欢创新的你又怎肯止步于此呢,当然,ASP.NET也不会止步于此。如果你需要一个全新的完全符合你的意愿的控件,那么你应该选择定制控件!
由此我们又要引出一个老套的话题,什么是定制控件呢?
定制控件的范围要比用户控件宽泛得多。首先,定制控件也就是CustomControl,主要可以分为三类:
继承自System.Web.UI.WebControls,这样创建的是一个全定制控件(full custom control); |
继承自现有控件,可以对现有控件的功能进行扩充,创建一个派生的定制控件(derived custom control); |
最后也可以像用户控件一样,把几个现有的控件组合在一起,创建一个合成定制控件(composite custom control),但与用户控件相比需要使用更有逻辑的结构。 |
其实,定制控件的特点是其自身包含在C#程序集(程序集的好处相信大家已经相当熟悉了,这是.NET的优势之一)中,不需要单独的ASP.NET代码,但却完全可以控制输出的内容,即控件生成的HTML。一般说来,开发定制控件要难于开发用户控件,不但语法要复杂一些,而且还要编写更多的代码才能得到结果。这些也算是创新所要付出的代价吧。
为了说明定制控件的特性,我们用表格的方式对用户控件和定制控件做一个比较:
|
定制控件 |
用户控件 |
组成元素 |
多个定制控件放在一个C#程序集中 |
一个用户控件是由一个.ascx文件和一个.cs后台代码文件组成 |
创建方式 |
在项目中添加一个控件库,添加C#代码,然后编译为C#程序集 |
在项目中添加用户控件,在.ascx文件中添加ASP.NET代码,在.cs后台代码文件中添加C#代码 |
引用方式 |
注册:<%@ Register TagPrefix="..." Namespace="..." Assembly="..."%>
引用:<TagPrefix:类名 ... |
注册:<%@ Register TagPrefix="..." TagName="..." Src="..."%>
引用:<TagPrefix:TagName ... |
创建的难易程度 |
复杂 |
简单 |
复用程度 |
复用性非常强,可以近似看成是一个类库。 |
不如定制控件强 |
从上面的表格中我们可以看出,定制控件与用户控件的区别还是比较大的,下面我们分别讨论一下:
C#程序集中可以存放多个定制控件,并且可以通过命名空间和类名唯一确定一个控件; |
C#程序集可以应用.NET系统固有的程序集动态查询,只要把程序集放在Web应用程序能够找到的地方(Web应用程序的bin目录下或者是全局程序集高速缓存[GAC]中),并进行注册即可使用; |
定制控件的每个方面都可以随意定制。但最好只为需要的功能编写代码,因为控件设计得越简单创建就越容易; |
定制控件使用方便,一但编译为程序集,我们甚至可以将它放到Visual Studio.NET的Toolbox中。 |
下面就让我们开始一起来讨论如何创建和使用定制控件。
定制控件的应用
首先我们在Visual Studio.NET中创建一个类型为Web Control Library的新项目,并且命名为"WebControls"如图所示:
我们为了简化测试,需要给同一Solution添加一个Web应用程序项目,并且命名为"WebControlsTestApp"。那么我们如果想在这个项目中使用上面创建的定制控件,就需要把控件库编译好的程序集copy到WebControlsTestApp中的bin目录下,并且添加引用,再进行注册。而其实还有更简单的方法,我们可以将控件库项目编译好的程序集直接输出到WebControlsTestApp中的bin目录下。想做到这点很简单,只需修改WebControls的属性页即可。在Solution Explorer中右击WebControls项目,在菜单中选择Properties。弹出如下对话框:
先将左上方的Configuration下拉菜单改为All Configuration,然后在左边列表框中选择Build,将右边的Output Path更改为WebControlsTestApp中的bin目录。再在左边列表框中选择Debugging,将右边的Debug Mode更改为URL;Start URL更改为http://localhost/WebControlsTestApp/WebForm1.aspx。
这样设置完成后,我们就可以方便地测试写好的定制控件了。下面我们来仔细看看上面创建的控件库。Visual Studio.NET在其中为我们默认创建了一个定制控件"WebCustomControl1"。我们来看一下它的内容(删去了XML文档注释):
using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel;
namespace WebControls { [DefaultProperty("Text"), ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")] public class WebCustomControl1 : System.Web.UI.WebControls.WebControl { private string text;
[Bindable(true), Category("Appearance"), DefaultValue("")] public string Text { get { return text; }
set { text = value; } }
protected override void Render(HtmlTextWriter output) { output.Write(Text); } } } |
我们来看这段代码,首先是命名空间的引入,然后声明了一个继承自System.Web.UI.WebControls.WebControl的类。这个类的前面有两个属性:DefaultProperty和ToolboxData。DefaultProperty属性是指定控件的默认特性。ToolboxData属性指定在使用Visual Studio.NET的Toolbox添加控件的条件下,为.aspx页面添加什么样的内容,其中的{0}占位符用于指定标记前缀的位置。
这个类包含一个属性:Text。
在其前面也包含三个属性:
Bindable 属性可否与数据绑定 |
Category 在属性页面上显示特性 |
DefaultValue 属性的默认值 |
剩下的就是一个Render方法,这个方法在设计定制控件时很重要,它访问输出流并控制控件显示内容。但也有不包含Render方法的情况。这样的控件要不就是没有可视化表示(通常称为组件),要不就是继承自其他控件并且不需要改变原有控件的显示特性。
然后我们将其编译,然后可以在Toolbox上右击,在弹出菜单中选择Add/Remove Items,在弹出的对话框中浏览到编译好的程序集,添加它,就可以把这个控件库中的定制控件全部添加到Toolbox中。这样就可以像使用已有控件一样使用自己制作的定制控件了。
添加后,我们将它拖到.aspx页面的design界面中。不难发现,这是一个标准的<asp:Label>控件。
那么现在就让我们对此控件进行一些有趣的改动。我们并不做太多改动,代码如下:
首先,我们在标准的命名空间下面添加一个using System.Drawing;命名空间引用,我们引入这个命名空间是为了可以取得一些颜色的值。然后我们再将Render方法改写如下:
protected override void Render(HtmlTextWriter output) { int[] rgb = {Color.Red.ToArgb() & 0xFFFFFF, Color.Blue.ToArgb() & 0xFFFFFF, Color.Green.ToArgb() & 0xFFFFFF};
for (int pos=0; pos<text.Length; pos++) { output.Write("<font color='#"+rgb[pos%3].ToString("X6")+"'>"+Text[pos]+"</font>"); } } |
我们在原有基础上添加了一些代码。如果你急着看效果那就按下Ctrl+Shift+B编译,然后给控件的Text属性赋上"ASP.NET的定制控件",再按F5运行一下,如图:
怎么样?还是挺有意思的吧。在这里我们只是添加了一个变色的功能,实现也非常简单,只是用一个数组去循环。但却也体现了一些定制控件的特性。你也可以马上再去扩充一下现有的功能,充分发挥你的想象力,因为ASP.NET的服务器控件的每一个方面都可以随你定制。它的功能之强,以至于要把它介绍明白写一本书也不为过。但是我们的水平有限,写书还是不想了。其实我们也只是想通过这篇文章,给大家添个思路,如果想深入研究请参照相关书籍。
总结
本文着重介绍了.NET中代码复用的相关内容,主要是用户控件和定制控件两部分,我们在这里通过一些实例介绍了他们的用法以及特性。而对于定制控件与传统ASP和com组件的比较,超出了本文讨论的范围,所以没有涉及(传统脚本对于已有对象的支持不足,所以效率和维护方面都不太好,至少在这点上C#的程序集是可以轻松超越的)。
最后让我们再来总结一下:
首先,我们介绍了创建简单的用户控件。它的优点就是可以最方便地实现代码的复用。 |
随后,我们介绍的比用户控件又进一步的定制控件,我们应用它可以定制ASP.NET服务器控件的任何方面。但创建它势必要更费功夫。 |
那么我们到底应该什么时候使用哪种控件呢?有的书上说像banner那样的元素,应该使用用户控件,而内部逻辑比较多的就应该使用定制控件。其实我觉得没有什么定则,完全要根据具体情况来分析决定。 |
此文是由我们两人合写的,由于首次合作写文章,所以不免有不足之处,还请各位读者多多包涵。
参考文献
[1] |
C#高级编程——第二版 |
[2] |
ASP.NET高级编程 |
[3] |
ASP.NET开发新思维 |
[4] |
ASP.NET服务器控件与组件编程 | |