演练:使用 ASP.NET 用户控件创建可重用元素
更新:2007 年 11 月
ASP.NET 用户控件使您能够封装一个单元中多个服务器控件的功能。用户控件由一个或多个 ASP.NET 服务器控件(Button 控件、TextBox 控件等)以及控件执行您希望完成的功能所需的任何代码组成。用户控件还可以包括自定义属性或方法,这些属性或方法向容器(通常为 ASP.NET 页)显示用户控件的功能。
在本演练中,将创建用作选择器控件的 ASP.NET 用户控件。此选择器控件有两个列表,一个列表(源)中有一组选择。用户可以在“SourceList”列表中选择项,然后将这些项添加到“TargetList”列表中。
本演练有三个部分,如下所示:
在第一部分中,将创建基本用户控件,添加控件和代码。
在第二部分中,将创建新的 ASP.NET 页(主页面),然后将用户控件添加到此 ASP.NET 页。
在第三部分中,将自定义属性和方法添加到用户控件,以便可以从主页面与控件交互。
本演练涉及以下任务:
创建用户控件,并将 ASP.NET 服务器控件添加到此用户控件。
在用户控件中创建属性和方法。
将用户控件添加到主页面。
向主页面添加代码以处理用户控件。
先决条件
为了完成本演练,您需要:
Microsoft Visual Web Developer 网站开发工具。
Microsoft .NET Framework。
本演练假设您大致了解如何使用 Visual Web Developer。有关介绍,请参见演练:在 Visual Web Developer 中创建基本网页。
创建网站
如果您已经在 Visual Web Developer 中创建了网站(例如,通过完成演练:在 Visual Web Developer 中创建基本网页),则可以使用该网站,并转至下一节。否则,按照下面的步骤创建一个新的网站和网页。
创建文件系统网站
打开 Visual Web Developer。
在“文件”菜单上指向“新建”,然后单击“网站”。
出现“新建网站”对话框。
在“Visual Studio 已安装的模板”之下单击“ASP.NET 网站”。
在最右边的“位置”框中输入要保存网站网页的文件夹的名称。
例如,键入文件夹名“C:\WebSites”。
在“语言”列表中,单击您想使用的编程语言。
单击“确定”。
Visual Web Developer 创建该文件夹和一个名为 Default.aspx 的新页。
创建用户控件
创建用户控件与创建 ASP.NET 网页相似。事实上,用户控件是 ASP.NET 页的子集,它可以包括放置到 ASP.NET 页的大多数类型的元素。
创建用户控件
在解决方案资源管理器中,右击网站的名称,然后单击“添加新项”。
在“添加新项 <路径>”对话框的“Visual Studio 已安装的模板”下,单击“Web 用户控件”。
在“名称”框中键入“ListPicker”。
用户控件文件的扩展名将为 .ascx,此扩展名自动添加到“ListPicker”。
在“语言”列表中,选择您想使用的编程语言。
单击“添加”。
即会创建新控件并将其在设计器中打开。控件的标记与页面的标记相似,最大的不同在于页面的顶部没有 @ Page 指令。而是有 @ Control 指令,此指令将该文件作为用户控件向 ASP.NET 标识。
将服务器控件添加到用户控件
在演练的此部分中,将添加组成用户控件的用户界面的控件。
添加服务器控件
切换到“设计”视图。(如果使用的是代码隐藏页,请切换到 ListPicker.ascx 控件,然后切换到“设计”视图。)
在“表”菜单上单击“插入表”。
使用“插入表”对话框,创建带有一行和三列的表格,然后单击“确定”。
正在创建用于保存控件的表,即布局表格。
在此表的左列中键入“Available”,然后按 Enter 以创建新行。
在右列中键入“Selected”,然后按 Enter 以创建新行。
从工具箱的“标准”组中,将以下控件拖到表中,然后按指示设置它们的属性。
控件
属性
将“ListBox”拖动到左列,并将其放置在“Available”下。
Height:200px
ID:SourceList
Width:200px
将“Button”拖动到中间列。
ID:AddAll
Text:>>
将“Button”拖动到中间列。
ID:AddOne
Text:(空格键)>(空格键)
将“Button”拖动到中间列。
ID:Remove
Text:(空格键)X(空格键)
将“ListBox”拖动到右列,并将其放置在“Selected”下。
Height:200px
ID:TargetList
Width:200px
可以使用 ImageButton 控件而不使用 Button 控件,以便单击鼠标时,显示一个响应此操作的图像。但在本演练中,只需使用模拟图形类型的文本,此图形类型常常用于指示 Add All、Add 和 Remove,分别为两个右尖括号 (>>)、一个右尖括号 (>) 和 X。
如有需要,根据所需调整表格列的宽度和高度。
单击“SourceList”列表,然后在“属性”中单击 Items 属性对应的省略号 (…) 按钮。
出现“ListItem 集合编辑器”对话框。
单击“添加”三次以添加三个项
在“ListItem properties”,分别为第一、第二和第三个项将“Text”设置为“A”、“B”和“C”。
现在创建的是测试数据。在本演练稍后部分的“将自定义属性和方法添加到用户控件”中,将会移除测试数据并添加代码以动态加载“SourceList”列表。
添加代码以处理用户选择
用户将使用表格中间列的按钮来选择项。因此,控件的大多数代码都位于 Click 事件的处理程序中。
添加代码以处理用户选择
在“设计”视图中,双击 >>(“AddAll”)按钮,为 Click 事件创建事件处理程序,然后添加以下突出显示的代码。
Protected Sub AddAll_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles AddAll.Click TargetList.SelectedIndex = -1 Dim li As ListItem For Each li In SourceList.Items AddItem(li) Next End Sub
protected void AddAll_Click(object sender, EventArgs e) { TargetList.SelectedIndex = -1; foreach(ListItem li in SourceList.Items) { AddItem(li); } }
此代码遍历“SourceList”列表中的所有列表项。它为每个项调用 AddItem 方法,并将此方法传递到当前项。在本过程的稍后部分,将编写 AddItem 方法的代码。
切换到“设计”视图,双击 >(“AddOne”)按钮,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub AddOne_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles AddOne.Click If SourceList.SelectedIndex >= 0 Then AddItem(SourceList.SelectedItem) End If End Sub
protected void AddOne_Click(object sender, EventArgs e) { if(SourceList.SelectedIndex >= 0) { AddItem(SourceList.SelectedItem); } }
此代码首先检查“SourceList”列表中是否有选定的内容。如果有,此代码调用 AddItem 方法(将在本过程的稍后部分编写此方法),将其传递到当前在“SourceList”列表中选定的项。
切换到“设计”视图,双击“X”(“Remove”)按钮,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub Remove_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles Remove.Click If TargetList.SelectedIndex >= 0 Then TargetList.Items.RemoveAt(TargetList.SelectedIndex) TargetList.SelectedIndex = -1 End If End Sub
protected void Remove_Click(object sender, EventArgs e) { if (TargetList.SelectedIndex >= 0) { TargetList.Items.RemoveAt(TargetList.SelectedIndex); TargetList.SelectedIndex = -1; } }
此代码首先检查“TargetList”列表中是否包含选定内容。如果有选定内容,此代码将选定项从列表和选定内容中移除。
添加下面的 AddItem 方法:
Protected Sub AddItem(ByVal li As ListItem) TargetList.SelectedIndex = -1 TargetList.Items.Add(li) End Sub
protected void AddItem(ListItem li) { TargetList.SelectedIndex = -1; TargetList.Items.Add(li); }
此代码无条件将项添加到“TargetList”列表。在本演练稍后部分的“将自定义属性和方法添加到用户控件”中,将添加选项来确定是否有重复,从而改进代码。
不能直接测试用户控件,因为它必须承载在某个页面中。在下一节中,将创建可以在其中使用控件的 ASP.NET 网页。
使用用户控件
和任何控件一样,用户控件必须承载在某个页面中。在演练的此部分中,将为控件创建主页面,然后将用户控件添加到此页面。
创建主页面
在解决方案资源管理器中,右击网站的名称,然后单击“添加新项”。
在“Visual Studio 已安装的模板”下单击“Web 窗体”。
在“名称”框中键入“HostUserControl”。
在“语言”列表中,选择您想使用的语言,然后单击“添加”。
新页面随即在设计器中出现。
将用户控件添加到页面
切换到“设计”视图。
从解决方案资源管理器中,将用户控件文件 (ListPicker.ascx) 拖动到页面上。
说明: 请确定将 ListPicker.ascx 拖动到页面上时处于“设计”视图。
控件即会在设计器中出现。
切换到“源”视图。
将用户控件放置到页面上将会在页面中创建两个新元素:
页面的顶部是一个新的 @ Register 指令,如下所示:
<%@ Register Src="ListPicker.ascx" TagName="ListPicker" TagPrefix="uc1" %>
@ Register 指令是必选的,因为用户控件是外部组件。指令中的值提供 ASP.NET 在编译和运行页面时查找控件所需的信息。TagPrefix 和 TagName 属性一起指定如何在页面中声明控件。Src 属性指定文件和源文件所在的路径(如有必要)。
第二个新元素是用户控件的元素,如下所示:
<uc1:ListPicker id="ListPicker1" Runat="server" />
用户控件的元素的外观与普通 ASP.NET 服务器控件的元素相似。区别在于用户控件具有不同的标记前缀 (uc1),并且有一个唯一的标记名称 (ListPicker)。尽管这些值是由 @ Register 指令在您将用户控件放置到页面时自动建立的,只要未在页面中使用这些值,就可以为用户控件使用任何标记前缀和标记名称。
测试用户控件
现在,可以测试用户控件的初步版本。
测试用户控件
按 Ctrl+F5 运行该页。
此页即会在浏览器中显示,可以看到组成用户控件的两个列表和三个按钮。
单击 >>(“AddAll”)按钮。
“SourceList”列表中的所有值即会复制到“TargetList”列表。
依次单击“TargetList”列表中的每个项,然后单击“X”(“Remove”)按钮,直至移除所有项为止。
在“SourceList”列表中选择一个值,然后单击 > (AddOne) 按钮。
即会将单个值复制到“TargetList”列表。
(可选)尽量多试用控件,直至确定达到您想要的效果为止。
完成后,关闭浏览器。
将自定义属性和方法添加到用户控件
您的用户控件现在可以使用,但它还不能用作通用控件。更实用的用户控件版本使您能够执行以下操作:
指定要在“SourceList”列表中动态显示的项列表。
获取用户在“TargetList”列表中选定的项列表。
指定是否允许“TargetList”列表中出现重复值(可选)。
为用户提供快速清除“TargetList”列表中所有项的方式。
执行这些任务要求主页面可以和用户控件通信,以便共享值(设置和读取属性)和发出命令(调用方法)。在演练的此部分中,将更改用户控件并向其添加一些成员(属性和方法)。
将两个属性添加到用户控件。第一个属性检索“TargetList”列表中的项列表。第二个属性使您能够指定“TargetList”列表是否接受重复值。在本节的稍后部分,将添加一个方法,此方法使您能够填充“SourceList”列表。
添加代码以定义自定义属性
对于“ListPicker”控件,打开或切换到代码文件。
使用下面的代码来创建 SelectedItems 属性:
Public ReadOnly Property SelectedItems() As ListItemCollection Get Return TargetList.Items End Get End Property
public ListItemCollection SelectedItems { get { return TargetList.Items ; } }
SelectedItems 属性检索“TargetList”列表中的值。它可以是只读的,因为永远无需以编程方式设置“TargetList”列表中的值。
使用下面的代码来创建 AllowDuplicates 属性:
Public Property AllowDuplicates() As Boolean Get Return CType(ViewState("allowDuplicates"), Boolean) End Get Set(ByVal value As Boolean) ViewState("allowDuplicates") = value End Set End Property
public Boolean AllowDuplicates { get { return (Boolean)ViewState["allowDuplicates"]; } set { ViewState["allowDuplicates"] = value; } }
AllowDuplicates 属性是一个读/写属性。必须在视图状态中显式保存 AllowDuplicates 属性的值,使得此值在往返行程中保持不变。(无需在视图状态中显式保存 SelectedItems 属性,因为“TargetList”列表在视图状态保存值。)
现在已经定义属性。但仍然必须修改用户控件中的现有代码,以便利用 AllowDuplicates 属性设置。
修改现有代码以使用 AllowDuplicates 属性
找到在本演练前面的“添加代码以处理用户选择”中编写的 AddItem 方法,用以下突出显示的代码替换其内容:
Protected Sub AddItem(ByVal li As ListItem) TargetList.Selectedindex = -1 If Me.AllowDuplicates = True Then TargetList.Items.Add(li) Else If TargetList.Items.FindByText(li.Text) Is Nothing Then TargetList.Items.Add(li) End If End If End Sub
protected void AddItem(ListItem li) { TargetList.SelectedIndex = -1; if (this.AllowDuplicates == true) { TargetList.Items.Add(li); } else { if (TargetList.Items.FindByText(li.Text) == null) { TargetList.Items.Add(li); } } }
代码执行的功能与先前相同(将项添加到“TargetList”列表),但现在代码检查以确定 AllowDuplicate 属性是否设置为 true。如果 AllowDuplicate 属性设置为 true,则会添加项。如果 AllowDuplicate 属性设置为 false,则代码将查找值与建议的新项的值相同的现有项,然后在找不到现有项时添加新项。
因为将使用属性设置“SourceList”列表的内容,可以移除在本演练前面的“将服务器控件添加到用户控件”中输入的测试数据。
从 SourceList 列表移除测试数据
切换到“设计”视图。
单击“SourceList”控件,然后在“属性”中,单击“项”对应的省略号 (…) 按钮。
出现“ListItem 集合编辑器”。
单击“移除”按钮以移除每个示例项,然后单击“确定”。
将方法添加到用户控件
还可以添加方法,以便主页面中的代码调用这些方法时在用户控件中执行任务。为了演示这一点,在本演练中,将添加两个方法。可以调用第一个方法将项添加到“SourceList”列表。第二个方法用于清除“TargetList”列表的内容。
添加方法以清除 TargetList 列表
使用下面的代码添加 AddSourceItem 方法:
Public Sub AddSourceItem(ByVal sourceItem As String) SourceList.Items.Add(sourceItem) End Sub
public void AddSourceItem(String sourceItem) { SourceList.Items.Add(sourceItem); }
使用下面的代码添加 ClearAll 方法:
Public Sub ClearAll() SourceList.Items.Clear() TargetList.Items.Clear() End Sub
public void ClearAll() { SourceList.Items.Clear(); TargetList.Items.Clear(); }
在“文件”菜单上,单击“全部保存”以保存对用户控件所作的更改。
测试用户控件属性和方法
本演练的最后一个任务是增强主页面,使其能够与用户控件共享值。可以以声明方式设置用户控件的部分属性。(不能使用本演练中的代码直接设置“SourceList”列表,但可以以编程方式设置。)在此过程中,会将 AllowDuplicates 属性设置为默认值 true。
以声明方式设置用户控件属性
切换到或打开 HostUserControl.aspx 页。
在“源”视图中,使用如下语法以声明方式设置“AllowDuplicates”:
<uc1:ListPicker id="ListPicker1" Runat="server" AllowDuplicates="true" />
请注意,获取“AllowDuplicates”的 Microsoft IntelliSense 功能。
以编程方式使用用户控件
还可以以编程方式使用用户控件,设置和检索属性以及调用方法。为了阐释如何以编程方式使用用户控件,将几个控件添加到主页面。
以编程方式使用用户控件
切换到“设计”视图。
从工具箱的“标准”组中,将以下控件拖动到主页面中的表格上,然后按如下所示设置属性。
控件
属性
TextBox
ID:NewItem
Text:(空)
Button
ID:AddItem
Text:Add Item
Button
ID:LoadFiles
Text:File List
Button
ID:ClearSelection
Text:Clear All
CheckBox
AutoPostBack:True
Checked:True
ID:AllowDuplicates
Text:Allow duplicates
Button
ID:ShowSelection
Text:Show Selection
Label
ID:Selection
Text:(空)
在“设计”视图中,双击“AllowDuplicates”,为 CheckedChanged 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub AllowDuplicates_CheckedChanged( _ ByVal sender As Object, _ ByVal e As EventArgs) Handles AllowDuplicates.CheckedChanged ListPicker1.AllowDuplicates = AllowDuplicates.Checked End Sub
protected void AllowDuplicates_CheckedChanged(Object sender, EventArgs e) { ListPicker1.AllowDuplicates = AllowDuplicates.Checked; }
切换到“设计”视图,双击“AddItem”,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub AddItem_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles AddItem.Click Dim sourceItem As String = Server.HtmlEncode(NewItem.Text) ListPicker1.AddSourceItem(sourceItem) End Sub
protected void AddItem_Click(object sender, EventArgs e) { ListPicker1.AddSourceItem(Server.HtmlEncode(NewItem.Text)); }
此代码在代码中创建一个 ListItemCollection 集合,并用示例数据填充此集合。然后,代码将 SourceItems 属性设置为该集合。
切换到“设计”视图,双击“LoadFiles”,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub LoadFiles_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles LoadFiles.Click Dim path As String = Server.MapPath(Request.ApplicationPath) Dim files() As String = System.IO.Directory.GetFiles(path) Dim filename As String For Each filename in Files ListPicker1.AddSourceItem(filename) Next End Sub
protected void LoadFiles_Click(object sender, EventArgs e) { String path = Server.MapPath(Request.ApplicationPath); String[] files = System.IO.Directory.GetFiles(path); foreach(String filename in files) { ListPicker1.AddSourceItem(filename); } }
此代码与“AddItem”的代码相似,不同之处在于此代码在网站的根目录中添加一个文件列表。
切换到“设计”视图,双击“ShowSelection”,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub ShowSelection_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles ShowSelection.Click Dim lItem As ListItem Dim selectedItemsString As String = "" For Each lItem in ListPicker1.SelectedItems selectedItemsString &= "<br>" & lItem.Text Next Selection.Text = selectedItemsString End Sub
protected void ShowSelection_Click(object sender, EventArgs e) { String selectedItemsString = ""; foreach(ListItem lItem in ListPicker1.SelectedItems) { selectedItemsString += "<br>" + lItem.Text; } Selection.Text = selectedItemsString; }
此代码检索键入为 ListItemCollection 对象的对象,读取集合中的每个项,然后在“选定内容”中显示结果。
切换到“设计”视图,双击“ClearSelection”,为 Click 事件创建一个事件处理程序,然后添加以下突出显示的代码:
Protected Sub ClearSelection_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles ClearSelection.Click ListPicker1.ClearAll() End Sub
protected void ClearSelection_Click(object sender, EventArgs e) { ListPicker1.ClearAll(); }
此代码调用用户控件的 ClearAll 方法,以便从“TargetList”中移除所有项。
测试已完成的用户控件
现在可以测试已完成的用户控件。
测试用户控件
按 Ctrl+F5 运行该页。
在文本框中键入一个值,然后单击“添加项”。
重复步骤 2 几次,直至在用户控件中具有选定的几项为止。
使用按钮从“SourceList”列表中选择一个或多个源项,然后将它们添加到“TargetList”列表。
单击“显示选定内容”。
“TargetList”列表项即会在“选定内容”中显示。
单击“全部清除”。
单击“文件列表”。
“SourceList”列表即会显示一个文件名列表。
在用户控件中单击“添加”,以便将多个项添加到“TargetList”列表。
尝试将某个已经在“TargetList”列表中的项添加到此列表。
即会添加重复值。
清除“允许重复”框,然后再次尝试添加重复项。
这一次,重复项不会添加到“TargetList”列表。
单击“显示选定内容”。
即会在主页面中显示“TargetList”列表中的项的列表。
后续步骤
尽管已经创建的控件不是很复杂,但您已经了解可以置入用户控件的许多基本功能。改善控件主要是显示用于增强控件功能的其他属性和方法。其他成员可能包括:
外观属性。
可以创建允许用户设置控件的背景、列表大小等的用户控件属性。
说明: 默认情况下,用户控件使用应用到子控件的当前主题。例如,如果为 Button 控件定义了一个外观,将会以该外观显示用户控件中的按钮。
数据属性。
可以添加一些属性,这些属性使用户控件能够使用更多种类的数据以在“SourceList”列表中显示。例如,可以添加属性以设置数据集、数据表和数据显示字段。
功能。
可以将更多按钮和代码添加到用户控件,使用户不仅能够将项从“SourceList”列表复制到“TargetList”列表,还可以移动项,即在将项移动到“TargetList”列表时,将其从“SourceList”列表中移除。这样,控件即具有将数据从“TargetList”列表移回“SourceList”列表的按钮。