页面上的控件 在添加了对包含
控件的
程序集的引用之后,您可以将 MailLink
控件拖动到设计器表面并像使用任何其他 ASP.NET 服务器
控件那样使用它。
 图 6. MailLink 自定义 控件 |
图 6 展示了 MailLink
控件的设计器视图。请注意,Properties 窗口公开了预期的 Email 和 Text 元素,它们可以用于配置
控件。通过将自定义
控件编译到可重复使用的
程序集中,MailLink
控件可以被很多 Web 应用
程序重复使用。
创建复合服务器控件 诸如 Login 和 GridView 这些可靠的
控件是由很多基本
控件组成的。在 ASP.NET 1.x 中,您必须通过艰苦的工作将嵌套标记和元素添加到自定义
控件中来开发复合
控件。在 ASP.NET 2.0 中,您可以通过扩展 System.Web.UI.WebControls.CompositeControl 类来构建复杂的复合
控件。CompositeControl 类提供了将多个
控件的输出合并到单个统一的
控件中所必需的框架。
管理复合
控件比管理基本自定义
控件稍微困难一些,因为复合
控件需要一些自定义布局的信息。复合
控件将它们的呈现和事件处理任务委托给构成
控件。子
组件的所有关联的适配器类也会被自动应用。这样,如果您具有适当的适配器,复合
控件将会在任何目标浏览器类型或设备上正确地呈现。
创建复合控件 创建复合
控件的初始过程与创建自定义服务器
控件的初始过程相似。但是,该过程还涉及了更多的步骤。在以下示例中,我们将创建一个由 Label 和 TextBox 组成的简单的复合 AgeCollector
控件,它旨在收集生日的信息。
复合
控件类应该通过从 CompositeControl 继承开始。
| public class AgeCollector : CompositeControl{} |
定义属性 对于我们的简单
控件,我们必须为标签 (Prompt) 和文本框 (DateOfBirth) 创建属性。
[Bindable(true), Category("Appearance"), DefaultValue("Please enter your date of birth:"), Description("Text to prompt user with.") Localizable(true)] public virtual String Prompt { get { string s = (string)ViewState["Prompt"]; return (s == null) ? String.Empty : s; } set { ViewState["Prompt"] = value; } } |
再一次,我们使用特性为属性提供说明和默认值。我们选择了使提示可以进行本地化,以便该
控件无论何时都可以用于要求进行国际化的应用
程序中。实际的提示可以绑定到包含语言特定文本的资源文件。
还必须定义 DateOfBirth 属性。但是,我们不是使用 String,而是使用 DateTime 数据类型来正确地存储日期。
[Bindable(true), Category("Appearance"), DefaultValue(""), Description("Date of Birth Input area")] public virtual DateTime DateOfBirth { get { bject o = ViewState["DateOfBirth"]; return (o == null) ? DateTime.Now : (DateTime)o; } set { ViewState["DateOfBirth"] = value; } } |
CreateChildControls 方法
我们的复合
控件由一个标签和一个文本框组成。我们无法使用简单
控件的技术来显示这两个标记,除非使用强制方式和 Render() 方法。因为我们希望利用自适应呈现并显示我们的两个
控件,所以我们需要覆盖内置到 CompositeControl 类中的 CreateChildControls() 方法。这种方法使我们可以定义
控件,并将我们的复合
控件的属性传递到要显示的单个
控件中。
protected override void CreateChildControls() { //Create and load the label Label lab1 = new Label(); lab1.Text = Prompt; lab1.ForeColor = this.ForeColor; this.Controls.Add(lab1);
//Add a line break between the label and text box Literal lit = new Literal(); lit.Text = ""; this.Controls.Add(lit);
//Add the Textbox TextBox tb = new TextBox(); tb.ID = "tb1"; tb.Text = DateOfBirth.ToString(); this.Controls.Add(tb);
//call the parent method base.CreateChildControls(); } |
请注意,我们必须初始化每个
控件、分配所有属性,然后将
控件添加到内置到 CompositeControl 类中的 Controls 集合。我们还使用了 Literal 对象将换行符置于标签和
控件之间。Literal 对象是非常简单的
控件,您可以使用它在功能元素之间插入原始 HTML。
请注意,我们还对基本方法进行了调用,以便确保我们的复合
控件具有内置到 CompositeControl 基类中的任何其他功能。尤其是,基本方法会强制 ASP.NET 将 Controls 集合的所有元素添加到
控件树中。如果我们忽略这个调用,或者将其置于我们方法的顶部,那么复合
控件将不会正确地生成。
完整的 AgeCollector 当我们的 AgeCollector
控件生成时,ASP.NET 将在每个子
控件上实际调用适当的方法,并将结果合并到复合
控件的输出中。换句话说,如果我们已正确地设计了简单
控件,那么该复合
控件就只是一个容器。自适应呈现模型将会自动应用到每个子
控件中。但是,实际的 CompositeControl 将不会被修改,因为它不包含需要更改的任何
控件。
以下是另一个实例,其中使用的适当方法 (CreateChildControls()) 利用了自适应呈现模型,而不是简单地在 WebControl 上重载 Render() 方法。由于自适应呈现模型和 CompositeControl 的特性,ASP.NET 2.0 节省了我们的开发时间、减少了代码行数并减少了很多的测试烦恼。只要我们知道元素
控件可通过特定适配器正确地生成,CompositeControl 将会通过该适配器正确地生成。
如果我们将
控件拖动到 ASP.NET 页面上并查看属性,我们将会看到具有 Prompt 和 DateOfBirth 属性的单个
控件。
 图 7. AgeCollector 使用 |
请注意,如果我们将复合
控件的 ForeColor 更改为红色,我们实际上更改了 Label 的 ForeColor。但是,我们尚未链接某些其他属性。例如,我们无法更改 DateOfBirth 字段的 ForeColor。换句话说,当您构建一个复合
控件时,您始终需要考虑应该公开哪些子
控件属性。