65.9K
CodeProject 正在变化。 阅读更多。
Home

动态添加和删除用户控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (30投票s)

2008 年 6 月 2 日

CPOL

3分钟阅读

viewsIcon

337742

downloadIcon

3971

动态添加和移除页面上的用户控件并保持控件状态。

引言

我经常发现自己需要重复使用一个用户输入表单,但我不知道会重复使用多少次。例如,假设您想让您网站上的用户上传图片,但您不知道他们要上传多少张图片。给用户一个“添加”按钮可以让它们动态地向页面添加任意数量的上传框。

如果您只想动态添加一个控件,这样就没问题了,但是如果您在复杂的布局中有多个控件怎么办?在这种情况下,处理此问题的最简单方法是将您想要添加的控件包装到一个用户控件中,然后动态地将该用户控件添加到您的页面中。我将向您展示如何执行此操作、如何删除用户控件以及如何访问用户控件中控件的值。

使用代码

首先,让我们创建一个用户控件并用几个控件填充它作为我们的“模板”。用户控件内容如下所示

    <table>
        <tr>
            <td>Textbox Example:</td>
            <td>
                <asp:TextBox ID="tbx1" runat="server" />
            </td>
        </tr>
        <tr>
            <td>Dropdown Example:</td>
            <td>
                <asp:DropDownList ID="ddl1" runat="server">
                    <asp:ListItem Text="Dropdown 1" />
                    <asp:ListItem Text="Dropdown 2" />
                    <asp:ListItem Text="Dropdown 3" />
                </asp:DropDownList>
            </td>
        </tr>
        <tr>
            <td>Checkbox Example:</td>
            <td>
                <asp:CheckBoxList ID="cbx1" runat="server">
                    <asp:ListItem Text="Checkbox 1" />
                    <asp:ListItem Text="Checkbox 2" />
                    <asp:ListItem Text="Checkbox 3" />
                </asp:CheckBoxList> 
            </td>
        </tr>
    </table>
    
    <asp:Button ID="btnRemove" runat="server" Text="Remove" />
    
    <hr />

现在,将事件处理程序添加到用户控件的代码隐藏中,以便我们可以在单击“删除”按钮时知道。

 Partial Class WebUserControl
    Inherits System.Web.UI.UserControl

    'Declare the event that we want to raise 
    '(we'll handle this in the parent page)
    Public Event RemoveUserControl As EventHandler


    Protected Friend Sub btnRemove_Click(ByVal sender As Object, _
              ByVal e As System.EventArgs) Handles btnRemove.Click
        'Raise this event so the parent page can handle it
        RaiseEvent RemoveUserControl(sender, e)
    End Sub
End Class

现在我们有了要显示的控件,我们将动态地将用户控件添加到另一个页面。

在页面加载中,我们需要做三件重要的事情。首先,我们需要确定哪个控件触发了回发。我们需要确保点击了“添加”按钮。

这需要在页面加载事件中完成,而不是在“添加”按钮的onclick事件中完成,因为 ASP.NET 页面生命周期的工作方式。如果我们尝试在“添加”按钮的onclick事件(而不是页面加载)中添加任何控件,这些值将在页面回发时被清除。

如果单击了“添加”按钮,接下来要做的就是增加要添加到页面的用户控件的数量,这样我们就可以知道要显示多少个控件。我将此值存储在一个Literal控件中以跨回发。

我们还需要附加一个事件处理程序来处理用户控件上的“删除”按钮,当它被单击时。这将从Panel中删除控件,并减少页面上的控件数量。

最后,一旦所有设置都完成,我们就可以将所有请求的用户控件动态加载到PlaceHolder控件中。

Protected Sub Page_Load(ByVal sender As Object, _
              ByVal e As System.EventArgs) Handles Me.Load
        AddAndRemoveDynamicControls()
    End Sub

    Private Sub AddAndRemoveDynamicControls()
        'Determine which control fired the postback event. 
        Dim c As Control = GetPostBackControl(Page)

        If Not IsNothing(c) Then
            'If the add button was clicked, increase 
            'the count to let the page know we want
            'to display an additional user control
            If c.ID.ToString = "btnAdd" Then
                ltlCount.Text = Convert.ToInt16(ltlCount.Text) + 1
            End If
        End If

        'Be sure everything in the placeholder control is cleared out
        ph1.Controls.Clear()

        Dim ControlID As Integer = 0

        'Since these are dynamic user controls, re-add them every time the page loads.
        For i As Integer = 0 To (Convert.ToInt16(ltlCount.Text) - 1)
            Dim DynamicUserControl As WebUserControl = _
                  LoadControl("WebUserControl.ascx")

            'If this particular control id has been deleted 
            'from the page, DO NOT use it again. If we do, it will
            'pick up the viewstate data from the old item that 
            'had this control id, instead of generating
            'a completely new control. Instead, increment 
            'the control ID so we're guaranteed to get a "new"
            'control that doesn't have any lingering information in the viewstate.
            While InDeletedList("uc" & ControlID) = True
                ControlID += 1
            End While

            'Note that if the item has not been deleted from the page, 
            'we DO want it to use the same control id
            'as it used before, so it will automatically maintain 
            'the viewstate information of the user control
            'for us.
            DynamicUserControl.ID = "uc" & ControlID

            'Add an event handler to this control to raise 
            'an event when the delete button is clicked
            'on the user control
            AddHandler DynamicUserControl.RemoveUserControl, _
                       AddressOf Me.HandleRemoveUserControl

            'Finally, add the user control to the panel
            ph1.Controls.Add(DynamicUserControl)

            'Increment the control id for the next round through the loop
            ControlID += 1
        Next
    End Sub

    Private Function InDeletedList(ByVal ControlID As String) As Boolean
        'Determine if the passed in user control ID 
        'has been stored in the list of controls that
        'were previously deleted off the page
        Dim DeletedList() As String = ltlRemoved.Text.Split("|")
        For i As Integer = 0 To DeletedList.GetLength(0) - 1
            If ControlID.ToLower = DeletedList(i).ToLower Then
                Return True
            End If
        Next
        Return False
    End Function

    Sub HandleRemoveUserControl(ByVal sender As Object, ByVal e As EventArgs)
        'This handles delete event fired from the user control

        'Get the user control that fired this event, and remove it
        Dim DynamicUserControl As WebUserControl = sender.parent
        ph1.Controls.Remove(sender.parent)

        'Keep a pipe delimited list of which user controls 
        'were removed. This will increase the 
        'viewstate size if the user keeps removing 
        'dynamic controls, but under normal use
        'this is such a small increase in size that it shouldn't be an issue.
        ltlRemoved.Text &= DynamicUserControl.ID & "|"

        'Also, now that we've removed a user control decrement 
        'the count of total user controls on the page
        ltlCount.Text = Convert.ToInt16(ltlCount.Text) - 1
    End Sub


    Protected Sub btnAdd_Click(ByVal sender As Object, _
              ByVal e As System.EventArgs) Handles btnAdd.Click
        'Handled in page load
    End Sub

这里还有一个问题。我们如何获取存储在用户控件中的值?这实际上非常简单。我们循环遍历PlaceHolder中的所有控件,然后查看控件的名称以确定这是否是我们要添加到PlaceHolder的用户控件之一。

如果是,我们可以使用FindControl来访问存储在文本框、下拉列表、复选框或添加到用户控件中的任何其他内容中的值。在这里,我正在获取这些值,然后将它们写入屏幕

Protected Sub btnDisplayValues_Click(ByVal sender As Object, _
          ByVal e As System.EventArgs) Handles btnDisplayValues.Click
        ltlValues.Text = ""
    For Each c As Control In ph1.Controls
        'Find the specific user control that we added to this 
        'placeholder, and then get the selected values
        'for the dropdownlist, checkbox, and textbox and print them to the screen.
        If c.GetType.Name.ToLower = "webusercontrol_ascx" Then
            Dim uc As UserControl = CType(c, UserControl)
            Dim tbx1 As TextBox = uc.FindControl("tbx1")
            Dim ddl1 As DropDownList = uc.FindControl("ddl1")
            Dim cbx1 As CheckBoxList = uc.FindControl("cbx1")

            Dim sb As New System.Text.StringBuilder
            sb.Append("Textbox value: " & tbx1.Text & "<br />")
            sb.Append("Dropdown value: " & ddl1.SelectedValue & "<br />")
            sb.AppendLine("Checkbox values: ")

            For Each li As ListItem In cbx1.Items
                If li.Selected = True Then
                    sb.Append(li.Value & "<br />")
                End If
            Next

            sb.Append("<hr />")

            ltlValues.Text &= sb.ToString
        End If
    Next
End Sub

我希望这为您提供了另一种思考如何动态添加和移除控件的方式。请享用!

© . All rights reserved.