演练:创建 Web 自定义控件
如果现有的 ASP.NET 服务器控件中没有一个符合应用程序的要求,则可以通过从一个基控件类派生来创建自定义控件。这些类提供服务器控件的所有基本功能,因此您可以将注意力集中在所需功能的编程上。
在本演练中,您将使用自定义 Label 控件的代码,Web Control Library 模板中默认包括该控件。该控件是从 WebControl 类派生的,其行为与标准的 Label 控件相同,同时具有添加的属性将 Text 属性的值呈现为超级链接。为了完成本演练,您将执行这些过程:
- 在同一个解决方案中创建两个项目,一个用于自定义的 Label 控件,一个用于使用和测试该控件的 Web 窗体页。
- 将该控件添加到工具箱中。
- 通过将自定义控件添加到 Web 窗体页来使用该控件。
- 为该控件创建自定义设计器。
- 在浏览器中测试该控件。
注意 Visual Basic 和 Visual C# .NET 的标准版没有提供“Web 控件库”模板。有关更多信息,请参见 Visual Basic 标准版功能或 Visual C# 标准版的功能。
本演练的重点不是编写控件的代码,而是在编写完代码后如何生成控件。
创建项目
第一步是使用自定义控件模板开始一个新项目及生成控件。
创建自定义控件
- 在“文件”菜单上指向“新建”,然后单击“项目”。
将出现“新建项目”对话框。
- 在“项目类型”窗格中选择“Visual Basic 项目”或“Visual C# 项目”。在“模板”窗格中选择“Web 控件库”。
- 将“名称”更改为 CustomLabel,然后单击“确定”。
创建了一个新项目,WebCustomControl1 在代码编辑器中打开。
默认情况下,自定义 Label 控件的代码包括在“Web 控件库”模板中。这是您将在本演练中使用的控件。
- 在“生成”菜单上,单击“生成 CustomLabel”来编译控件。
控件编译为 CustomLabel.dll。默认情况下,它是在 CustomLabel 项目文件夹的 Bin 文件夹中创建的。
- 保存该文件。
既已创建了该控件,您将一个 Web 窗体页添加到相同的解决方案,使该页便于对该控件进行测试。
创建 Web 窗体页
- 在“文件”菜单上指向“添加项目”,然后单击“新建项目”。
出现“添加新项目”对话框。
- 在“项目类型”窗格中选择“Visual Basic 项目”或“Visual C# 项目”。在“模板”窗格中选择“ASP.NET Web 应用程序”。
- 在“位置”框中,为应用程序输入完整的 URL(包含 http:// 和服务器名称)。URL 的最后一部分是项目的名称;对于本演练,将项目命名为 LabelWebForm。Web 服务器上必须安装 IIS 5 版(或更高版本)和 .NET Framework。如果计算机上已安装 IIS,可以为服务器指定
http://localhost
。(如果正常使用代理服务器访问 Internet,为了使用本地主机,可能需要配置 Internet Explorer 以绕过代理服务器。) - 单击“确定”。
创建了新项目,WebForm1 在设计器中打开。
- 保存该项目。
将控件添加到工具箱
既已编译了控件并具有了可用来测试该控件的 Web 窗体页,您便可以将该控件添加到工具箱,以便它随时可供使用。
将控件添加到工具箱
- 在“工具”菜单上,单击“添加/移除工具箱项”。
- 在“自定义工具箱”对话框的“.NET Framework 组件”选项卡上,单击“浏览”按钮。查找 CustomLabel.dll,选中它,然后单击“打开”将 WebCustomControl1 添加到“自定义工具箱”对话框中组件的列表。
- 在 .NET Framework 组件列表中选择 WebCustomControl1,然后单击“确定”。WebCustomControl1 被添加到工具箱中。
完成后,您应该看到工具栏上的一个图标,如下所示:
下一步是在页中测试该控件。
将控件添加到 Web 窗体页并测试该控件
- 在“设计”视图中打开 WebForm1,然后从工具箱中将 WebCustomControl1 拖到该页上。
控件的默认呈现(仅仅是控件的名称和其后的控件 ID)出现在“设计”视图上。
- 切换到“HTML”视图,然后验证控件程序集的 @ Register 指令是否已添加到页的 HTML 中,其 TagPrefix 为“cc1”。
- 将控件的 Text 属性设置为 Hello。
“设计”视图中控件的外观被更新以显示新文本。
然后,您将自定义控件,因此需要将其从工具箱中移除。
从工具箱中移除控件
- 右击工具箱中的 WebCustomControl1,然后单击快捷菜单上的“删除”。该操作将不从项目中删除控件,只从工具箱删除控件。
- 关闭该 Web 窗体页而不保存。
现在自定义 Label 控件可以发挥作用了,但它不是很美观,并且在代码中不能明显区分出该标记。下一步是对控件进行个性化。
个性化控件
该控件正在使用工具箱中的默认图标,默认的标记前缀是“cc1”。为了使控件更加便于识别,请更改标记前缀并创建一个新图标。
更改标记前缀
- 在解决方案资源管理器中 CustomLabel 项目下,双击“AssemblyInfo”以在设计器中打开 AssemblyInfo 文件。在 AssemblyInfo 页的顶部添加 Imports 语句(在 Visual Basic 中)或 using 语句(在 Visual C# 中):
' Visual Basic Imports System.Web.UI // C# using System.Web.UI;
- 将 Assembly: TagPrefix 属性添加到程序集属性的列表。这将指定 CustomLabel 控件的新 TagPrefix,在本例中为 xxx。
' Visual Basic <Assembly: TagPrefix("CustomLabel", "xxx")> //C# [assembly: TagPrefix("CustomLabel", "xxx")]
创建新图标
- 在解决方案资源管理器中选择“CustomLabel”项目。在“项目”菜单上单击“添加新项”。
将出现“添加新项”对话框。
- 在“模板”窗格中选择“位图文件”,将“名称”更改为 WebCustomControl1.bmp,然后单击“打开”。新位图文件出现在解决方案资源管理器中并在设计器中打开。
注意 对于此演练,图标文件的名称必须与控件类的名称 (WebCustomControl1) 完全匹配,包括大小写。
- 在“属性”窗口中,将位图的 Height 和 Width 属性更改为 16。图标的大小必须为 16 乘 16 像素。
- 在位图上画一个独特的图案,使用多种颜色,以便您可以识别该图标。
- 保存并关闭位图文件。
- 在解决方案资源管理器中选择 WebCustomControl1.bmp。在“属性”窗口中,将“生成操作”属性更改为“嵌入的资源”。
- 在解决方案资源管理器中选择“CustomLabel”项目。在“生成”菜单上,单击“重新生成 CustomLabel”。
- 保存所有的工作。
如果现在将该控件添加到工具箱,则您创建的图标将显示在控件名称的旁边。当在 Web 窗体页上使用该控件时,控件的 HTML 标记将包含您指定的标识前缀。
使用自定义控件
- 再次将 WebCustomControl1 添加到工具箱。
显示控件,带有您创建的图标。根据您的设置,它可能显示在工具箱“常规”选项卡的下面。
- 重新打开名为 WebForm1 的 Web 窗体页并将该控件拖到其上。
注意 因为您先前关闭了 Web 窗体页而未进行保存,所以 Text 属性已恢复为默认值。
- 切换到“HTML”视图并验证 @ Register 指令的 TagPrefix 属性是否为 xxx。
- 因为您将对控件进行其他修改,所以从 Web 窗体页中删除 WebCustomControl1,但将其保留在工具箱中。
您的自定义控件现在已经完全可用并完成了个性化,但它在设计图面上的外观并不是很美观。要使控件更好看一些,您将向它添加一个自定义设计器。
创建自定义设计器
设计器是允许您修改组件和控件的设计时外观和行为的类。虽然所有所见即所得 (WYSIWYG) 窗体设计器的通常目标是尽量减小设计时外观和运行时外观之间的差异,但有时也需要特殊的设计时提示。有关更多信息,请参见自定义设计器。
在本演练中,您将实现一个自定义的设计器,该设计器使自定义控件将其文本呈现为超级链接。
创建控件的自定义设计器
- 在解决方案资源管理器中选择“CustomLabel”项目。
- 在“项目”菜单上,单击“添加引用”并将引用添加到 System.Design.dll。
- 在“项目”菜单上单击“添加新项”。
将出现“添加新项”对话框。
- 在“模板”窗格中选择“类”,将“名称”更改为 SampleDesigner,然后单击“打开”。新的类文件显示在解决方案资源管理器中,并在设计器中打开。
- 添加代码,该代码重写基类的 GetDesignTimeHtml 方法。设计时调用该方法以获取控件的表示形式。在重写的方法中,执行下列操作:
- 获取自定义控件的 Text 属性。
- 如果已设置了 Text 属性(也就是说,它不是一个空字符串),则创建一个新的 Hyperlink 控件,设置其属性来匹配原始控件,然后调用 Hyperlink 控件的 Render 方法。
最终结果是 Hyperlink 控件使用 Text 属性的值显示在设计器中。
执行这些步骤的代码如下所示,这完整地列出了 SampleDesigner 文件:
' Visual Basic Imports System Imports System.IO Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Web.UI.Design Public Class SampleDesigner Inherits System.Web.UI.Design.ControlDesigner Public Overrides Function GetDesignTimeHtml() As String ' Component is the control instance, defined in the base ' designer Dim ctl As WebCustomControl1 = CType(Me.Component, _ WebCustomControl1) If (ctl.Text <> "") Then Dim sw As New StringWriter() Dim tw As New HtmlTextWriter(sw) Dim placeholderlink As New HyperLink() ' put control text into the link's Text placeholderlink.Text = ctl.Text placeholderlink.NavigateUrl = ctl.Text placeholderlink.RenderControl(tw) Return sw.ToString() Else Return Me.GetEmptyDesignTimeHtml() End If End Function End Class // C# using System; using System.IO; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.Design; namespace CustomLabel { public class SampleDesigner : System.Web.UI.Design.ControlDesigner { public override string GetDesignTimeHtml() { // Component is the control instance, defined in the base // designer WebCustomControl1 ctl = (WebCustomControl1 ) Component; if (ctl.Text != "" && ctl.Text != null) { StringWriter sw = new StringWriter(); HtmlTextWriter tw = new HtmlTextWriter(sw); HyperLink placeholderLink = new HyperLink(); // put control text into the link's Text placeholderLink.Text = ctl.Text; placeholderLink.NavigateUrl = ctl.Text; placeholderLink.RenderControl(tw); return sw.ToString(); } else return GetEmptyDesignTimeHtml(); } } }
- (根据您正在使用的语言)在设计器中打开 WebCustomControl1.vb 或 WebCustomControl1.cs,然后将该属性紧接在 WebCustomControl1 类声明之前添加到属性列表中:
Designer("CustomLabel.SampleDesigner, CustomLabel")
WebCustomControl1 类声明应该如下所示:
' Visual Basic <Designer("CustomLabel.SampleDesigner, CustomLabel"), _ DefaultProperty("Text"), ToolboxData("<{0}:WebCustomControl1 _ runat=server></{0}:WebCustomControl1>")> Public Class WebCustomControl1 // C# [Designer("CustomLabel.SampleDesigner, CustomLabel"), DefaultProperty("Text"), ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")] public class WebCustomControl1 : System.Web.UI.WebControls.WebControl
- 在“生成”菜单上,单击“生成解决方案”,这样便生成了两个项目。
- 保存并关闭所有打开的文件。
测试控件
测试 Text 属性是否正常工作
- 在设计器中打开 WebForm1。
- 将 WebCustomControl1 从工具箱拖到该页上。
- 将 Web 自定义控件的 Text 属性设置为 Hello。该文本控件应该显示为 Web 窗体页上的超级链接。
- 保存 WebForm1。
在浏览器中测试控件
- 在解决方案资源管理器中选择 WebForm1。在“文件”菜单上单击“在浏览器中查看”。
- 验证 Hello 是否显示在浏览器中。文本看起来像一个标签,而不像超级链接。
注意 在 Visual Studio 中,您的代码在设计时总是完全受信运行的,即使该代码最终位于一个运行时未受到完全信任的项目中。这意味着当您在自己的计算机上测试自定义控件时,它可能会正确运行,但在部署的应用程序中,该自定义控件可能会因为权限不足而失败。务必要在安全上下文(即控件在实际应用程序中运行时所处的上下文)中对您的控件进行测试。