演练:使用 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 中创建基本网页),则可以使用该网站,并转至下一节。否则,按照下面的步骤创建一个新的网站和网页。

创建文件系统网站

  1. 打开 Visual Web Developer。

  2. 在“文件”菜单上指向“新建”,然后单击“网站”。

    出现“新建网站”对话框。

  3. 在“Visual Studio 已安装的模板”之下单击“ASP.NET 网站”。

  4. 在最右边的“位置”框中输入要保存网站网页的文件夹的名称。

    例如,键入文件夹名“C:\WebSites”。

  5. 在“语言”列表中,单击您想使用的编程语言。

  6. 单击“确定”。

    Visual Web Developer 创建该文件夹和一个名为 Default.aspx 的新页。

创建用户控件

创建用户控件与创建 ASP.NET 网页相似。事实上,用户控件是 ASP.NET 页的子集,它可以包括放置到 ASP.NET 页的大多数类型的元素。

创建用户控件

  1. 在解决方案资源管理器中,右击网站的名称,然后单击“添加新项”。

  2. 在“添加新项 <路径>”对话框的“Visual Studio 已安装的模板”下,单击“Web 用户控件”。

  3. 在“名称”框中键入“ListPicker”。

    用户控件文件的扩展名将为 .ascx,此扩展名自动添加到“ListPicker”。

  4. 在“语言”列表中,选择您想使用的编程语言。

  5. 单击“添加”。

    即会创建新控件并将其在设计器中打开。控件的标记与页面的标记相似,最大的不同在于页面的顶部没有 @ Page 指令。而是有 @ Control 指令,此指令将该文件作为用户控件向 ASP.NET 标识。

将服务器控件添加到用户控件

在演练的此部分中,将添加组成用户控件的用户界面的控件。

添加服务器控件

  1. 切换到“设计”视图。(如果使用的是代码隐藏页,请切换到 ListPicker.ascx 控件,然后切换到“设计”视图。)

  2. 在“表”菜单上单击“插入表”。

  3. 使用“插入表”对话框,创建带有一行和三列的表格,然后单击“确定”。

    正在创建用于保存控件的表,即布局表格。

  4. 在此表的左列中键入“Available”,然后按 Enter 以创建新行。

  5. 在右列中键入“Selected”,然后按 Enter 以创建新行。

  6. 从工具箱的“标准”组中,将以下控件拖到表中,然后按指示设置它们的属性。

    控件

    属性

    将“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。

  7. 如有需要,根据所需调整表格列的宽度和高度。

  8. 单击“SourceList”列表,然后在“属性”中单击 Items 属性对应的省略号 (…) 按钮。

    出现“ListItem 集合编辑器”对话框。

  9. 单击“添加”三次以添加三个项

  10. 在“ListItem properties”,分别为第一、第二和第三个项将“Text”设置为“A”、“B”和“C”。

    现在创建的是测试数据。在本演练稍后部分的“将自定义属性和方法添加到用户控件”中,将会移除测试数据并添加代码以动态加载“SourceList”列表。

添加代码以处理用户选择

用户将使用表格中间列的按钮来选择项。因此,控件的大多数代码都位于 Click 事件的处理程序中。

添加代码以处理用户选择

  1. 在“设计”视图中,双击 >>(“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 方法的代码。

  2. 切换到“设计”视图,双击 >(“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”列表中选定的项。

  3. 切换到“设计”视图,双击“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”列表中是否包含选定内容。如果有选定内容,此代码将选定项从列表和选定内容中移除。

  4. 添加下面的 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 网页。

使用用户控件

和任何控件一样,用户控件必须承载在某个页面中。在演练的此部分中,将为控件创建主页面,然后将用户控件添加到此页面。

创建主页面

  1. 在解决方案资源管理器中,右击网站的名称,然后单击“添加新项”。

  2. 在“Visual Studio 已安装的模板”下单击“Web 窗体”。

  3. 在“名称”框中键入“HostUserControl”。

  4. 在“语言”列表中,选择您想使用的语言,然后单击“添加”。

    新页面随即在设计器中出现。

将用户控件添加到页面

  1. 切换到“设计”视图。

  2. 从解决方案资源管理器中,将用户控件文件 (ListPicker.ascx) 拖动到页面上。

    说明:

    请确定将 ListPicker.ascx 拖动到页面上时处于“设计”视图。

    控件即会在设计器中出现。

  3. 切换到“源”视图。

    将用户控件放置到页面上将会在页面中创建两个新元素:

    • 页面的顶部是一个新的 @ 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 指令在您将用户控件放置到页面时自动建立的,只要未在页面中使用这些值,就可以为用户控件使用任何标记前缀和标记名称。

测试用户控件

现在,可以测试用户控件的初步版本。

测试用户控件

  1. 按 Ctrl+F5 运行该页。

    此页即会在浏览器中显示,可以看到组成用户控件的两个列表和三个按钮。

  2. 单击 >>(“AddAll”)按钮。

    “SourceList”列表中的所有值即会复制到“TargetList”列表。

  3. 依次单击“TargetList”列表中的每个项,然后单击“X”(“Remove”)按钮,直至移除所有项为止。

  4. 在“SourceList”列表中选择一个值,然后单击 > (AddOne) 按钮。

    即会将单个值复制到“TargetList”列表。

  5. (可选)尽量多试用控件,直至确定达到您想要的效果为止。

  6. 完成后,关闭浏览器。

将自定义属性和方法添加到用户控件

您的用户控件现在可以使用,但它还不能用作通用控件。更实用的用户控件版本使您能够执行以下操作:

  • 指定要在“SourceList”列表中动态显示的项列表。

  • 获取用户在“TargetList”列表中选定的项列表。

  • 指定是否允许“TargetList”列表中出现重复值(可选)。

  • 为用户提供快速清除“TargetList”列表中所有项的方式。

执行这些任务要求主页面可以和用户控件通信,以便共享值(设置和读取属性)和发出命令(调用方法)。在演练的此部分中,将更改用户控件并向其添加一些成员(属性和方法)。

将两个属性添加到用户控件。第一个属性检索“TargetList”列表中的项列表。第二个属性使您能够指定“TargetList”列表是否接受重复值。在本节的稍后部分,将添加一个方法,此方法使您能够填充“SourceList”列表。

添加代码以定义自定义属性

  1. 对于“ListPicker”控件,打开或切换到代码文件。

  2. 使用下面的代码来创建 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”列表中的值。

  3. 使用下面的代码来创建 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 列表移除测试数据

  1. 切换到“设计”视图。

  2. 单击“SourceList”控件,然后在“属性”中,单击“项”对应的省略号 (…) 按钮。

    出现“ListItem 集合编辑器”。

  3. 单击“移除”按钮以移除每个示例项,然后单击“确定”。

将方法添加到用户控件

还可以添加方法,以便主页面中的代码调用这些方法时在用户控件中执行任务。为了演示这一点,在本演练中,将添加两个方法。可以调用第一个方法将项添加到“SourceList”列表。第二个方法用于清除“TargetList”列表的内容。

添加方法以清除 TargetList 列表

  1. 使用下面的代码添加 AddSourceItem 方法:

    Public Sub AddSourceItem(ByVal sourceItem As String)
        SourceList.Items.Add(sourceItem)
    End Sub
    
    public void AddSourceItem(String sourceItem)
    {
        SourceList.Items.Add(sourceItem);
    }
    
  2. 使用下面的代码添加 ClearAll 方法:

    Public Sub ClearAll()
        SourceList.Items.Clear()
        TargetList.Items.Clear()
    End Sub
    
    public void ClearAll()
    {
        SourceList.Items.Clear();
        TargetList.Items.Clear();
    }
    
  3. 在“文件”菜单上,单击“全部保存”以保存对用户控件所作的更改。

测试用户控件属性和方法

本演练的最后一个任务是增强主页面,使其能够与用户控件共享值。可以以声明方式设置用户控件的部分属性。(不能使用本演练中的代码直接设置“SourceList”列表,但可以以编程方式设置。)在此过程中,会将 AllowDuplicates 属性设置为默认值 true。

以声明方式设置用户控件属性

  1. 切换到或打开 HostUserControl.aspx 页。

  2. 在“源”视图中,使用如下语法以声明方式设置“AllowDuplicates”:

    <uc1:ListPicker id="ListPicker1" Runat="server"
        AllowDuplicates="true" />
    

    请注意,获取“AllowDuplicates”的 Microsoft IntelliSense 功能。

以编程方式使用用户控件

还可以以编程方式使用用户控件,设置和检索属性以及调用方法。为了阐释如何以编程方式使用用户控件,将几个控件添加到主页面。

以编程方式使用用户控件

  1. 切换到“设计”视图。

  2. 从工具箱的“标准”组中,将以下控件拖动到主页面中的表格上,然后按如下所示设置属性。

    控件

    属性

    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:(空)

  3. 在“设计”视图中,双击“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;
    }
    
  4. 切换到“设计”视图,双击“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 属性设置为该集合。

  5. 切换到“设计”视图,双击“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”的代码相似,不同之处在于此代码在网站的根目录中添加一个文件列表。

  6. 切换到“设计”视图,双击“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 对象的对象,读取集合中的每个项,然后在“选定内容”中显示结果。

  7. 切换到“设计”视图,双击“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”中移除所有项。

测试已完成的用户控件

现在可以测试已完成的用户控件。

测试用户控件

  1. 按 Ctrl+F5 运行该页。

  2. 在文本框中键入一个值,然后单击“添加项”。

  3. 重复步骤 2 几次,直至在用户控件中具有选定的几项为止。

  4. 使用按钮从“SourceList”列表中选择一个或多个源项,然后将它们添加到“TargetList”列表。

  5. 单击“显示选定内容”。

    “TargetList”列表项即会在“选定内容”中显示。

  6. 单击“全部清除”。

  7. 单击“文件列表”。

    “SourceList”列表即会显示一个文件名列表。

  8. 在用户控件中单击“添加”,以便将多个项添加到“TargetList”列表。

  9. 尝试将某个已经在“TargetList”列表中的项添加到此列表。

    即会添加重复值。

  10. 清除“允许重复”框,然后再次尝试添加重复项。

    这一次,重复项不会添加到“TargetList”列表。

  11. 单击“显示选定内容”。

    即会在主页面中显示“TargetList”列表中的项的列表。

后续步骤

尽管已经创建的控件不是很复杂,但您已经了解可以置入用户控件的许多基本功能。改善控件主要是显示用于增强控件功能的其他属性和方法。其他成员可能包括:

  • 外观属性。

    可以创建允许用户设置控件的背景、列表大小等的用户控件属性。

    说明:

    默认情况下,用户控件使用应用到子控件的当前主题。例如,如果为 Button 控件定义了一个外观,将会以该外观显示用户控件中的按钮。

  • 数据属性。

    可以添加一些属性,这些属性使用户控件能够使用更多种类的数据以在“SourceList”列表中显示。例如,可以添加属性以设置数据集、数据表和数据显示字段。

  • 功能。

    可以将更多按钮和代码添加到用户控件,使用户不仅能够将项从“SourceList”列表复制到“TargetList”列表,还可以移动项,即在将项移动到“TargetList”列表时,将其从“SourceList”列表中移除。这样,控件即具有将数据从“TargetList”列表移回“SourceList”列表的按钮。

请参见

任务

如何:将 Web 窗体页转换为 ASP.NET 用户控件

概念

ASP.NET 用户控件概述

Web 应用程序安全威胁概述