【问题标题】:How do i get access to checkboxes dynamically generated in loop如何访问循环中动态生成的复选框
【发布时间】:2026-02-03 07:50:01
【问题描述】:

我是 asp.net 和 vb.net 编程的新手,我找不到我的问题的答案。我在运行时在一个循环中动态生成了一个复选框。

这是一个网格调度程序,它显示从不同页面选择的位置的选定日期和选定时间。我想通过 id 访问复选框,但我无法访问它们,因为复选框未在类级别声明。

谁能帮帮我,我整天都在寻找解决方案。我更喜欢 VB,但 C# 也很好。

下面是我的代码

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not IsPostBack Then
      BindLocationDayTime()
   End If
End Sub

Public Sub BindLocationDayTime()
        Dim ID As Integer
        Dim Name As String
        Dim Day As Integer
        Dim Time As Integer
        Dim StartDate As DateTime
        Dim EndDate As DateTime

        Dim Locations As SqlDataReader = GetLocations()

        For Each Item In Locations

            Dim LRow As New TableRow()
            Dim LCell As New TableCell()
            LCell.Text = Locations.Item("Name")
            LCell.Attributes.Add("class", "LocationHeader")
            LCell.Attributes.Add("colspan", "5")
            LRow.Cells.Add(LCell)
            LocationData.Rows.Add(LRow)

            Dim Location As SqlDataReader = GetLocation(Convert.ToInt32(Locations.Item("Id")))

            While Location.Read()
                Name = Location("Name").ToString()
                StartDate = Location("StartDate")
                EndDate = Location("EndDate")
            End While

            Dim dtfi As Globalization.DateTimeFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat
            Dim tRowCount As Integer = 0

            Do While StartDate <= EndDate
                Dim LocationDayTime As SqlDataReader = GetPlayDayTime(Convert.ToInt32(Locations.Item("Id")))

                For Each row In LocationDayTime
                    Day = LocationDayTime.Item("DayID")
                    Time = LocationDayTime.Item("TimeID")
                    ID = Locations.Item("Id")
                    If Day = 1 Then
                        If StartDate.DayOfWeek = DayOfWeek.Monday Then
                            BindDays(StartDate, ID, tRowCount, Time)
                            tRowCount = tRowCount + 1
                        End If
                    ElseIf Day = 2 Then
                        If StartDate.DayOfWeek = DayOfWeek.Tuesday Then
                            BindDays(StartDate, ID, tRowCount, Time)
                            tRowCount = tRowCount + 1
                        End If
                    ElseIf Day = 3 Then
                        If StartDate.DayOfWeek = DayOfWeek.Wednesday Then
                            BindDays(StartDate, ID, tRowCount, Time)
                            tRowCount = tRowCount + 1
                        End If
                    ElseIf Day = 4 Then
                        If StartDate.DayOfWeek = DayOfWeek.Thursday Then
                            BindDays(StartDate, ID, tRowCount, Time)
                            tRowCount = tRowCount + 1
                        End If
                    ElseIf Day = 5 Then
                        If StartDate.DayOfWeek = DayOfWeek.Friday Then
                            BindDays(StartDate, ID, tRowCount, Time)
                            tRowCount = tRowCount + 1
                        End If
                    End If
                Next
                StartDate = StartDate.AddDays(1)
            Loop
        Next
    End Sub

Public Sub BindDays(ByVal StartDate As DateTime, ByVal ID As Integer, ByVal tRowCount As Integer, ByVal Time As Integer)
        Dim dtfi As Globalization.DateTimeFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat
        Dim tRow As New TableRow()

        Dim Cell1 As New TableCell()
        Dim strDayOfWeek As String = dtfi.GetDayName(StartDate.DayOfWeek)
        Cell1.Text = UppercaseFirstLetter(strDayOfWeek & " ") & (StartDate.Date.ToShortDateString & " om ") & (Time & "uur ")
        Cell1.Attributes.Add("class", "MemberCell")
        tRow.Cells.Add(Cell1)

        Dim Cell2 As New TableCell()
        Dim cbAvailible As New CheckBox()
        cbAvailible.ID = (StartDate.Date) & "," & (Time)
        cbAvailible.Checked = False
        Cell2.Controls.Add(cbAvailible)
        tRow.Cells.Add(Cell2)

        Dim Cell3 As New TableCell()
        Dim Label As New Label()
        Label.Text = ("(Op deze datum ben ik verhinderd)")
        Cell3.Controls.Add(Label)
        tRow.Cells.Add(Cell3)

        If tRowCount Mod 2 Then
            tRow.Attributes.Add("class", "alternatingItemStyle")
        Else
            tRow.Attributes.Add("class", "itemStyle")
        End If

        LocationData.Rows.Add(tRow)

    End Sub

#End Region

#Region " Events "

Private Sub Insert_Click(sender As Object, e As EventArgs) Handles Insert.Click
' I want to get here al the checkbox id and insert the values to a databse
End Sub

End Region

【问题讨论】:

    标签: asp.net vb.net checkbox


    【解决方案1】:

    解决方案 1 - 使用递归控制搜索

    我已经对动态生成的表单进行了类似的操作,该表单具有可变数量的控件(文本框、下拉菜单和复选框),并且控件状态由数据驱动。我不希望与生成的控件的事件相关联(需要一个生涩的回发),但有一个“保存”按钮,并从该事件执行一个递归 GetChildControls 函数,该函数从包含动态控件的容器开始。在为每个动态控件分配 id 时有一个约定,这样当您稍后循环它们时,您可以知道哪个控件与哪个记录相关。

    递归函数:

    Public Class ControlUtils
        Shared Function GetChildControls(ByVal ctrl As Control, Optional ByVal ctrlType As Type = Nothing) As Control()
            Dim controls As New ArrayList()
            For Each c As Control In ctrl.Controls
                ' add this control and all its nested controls
                If ctrlType Is Nothing OrElse ctrlType.IsAssignableFrom(c.GetType()) Then
                    controls.Add(c)
                    controls.AddRange(GetChildControls(c))
                End If
            Next
            ' return the result as an array of Controls
            Return DirectCast(controls.ToArray(GetType(Control)), Control())
        End Function
    End Class
    

    具有人为动态形式的基本思想...

    表示数据库信息的类:

    Public Class Location
        Public Property ID As Integer
        Public Property Name As String
        Public Property StartDate As Date
        Public Property EndDate As Date
    
        Shared Function GetSampleLocations() As List(Of Location)
            Dim sample As New List(Of Location)
            Dim loc As Location
            For j = 1 To 5
                loc = New Location
                loc.ID = j
                loc.Name = "Location " & j
                loc.StartDate = Date.Today
                loc.EndDate = Date.Today.AddDays(6 - j)
                sample.Add(loc)
            Next
            Return sample
        End Function
    End Class
    

    具有构建“表单”并保存其数据的方法的类:

    Public Class LocationsDynamicForm
    
        Dim _Locations As IEnumerable(Of Location)
    
        Sub New(locations As IEnumerable(Of Location))
            _Locations = locations
        End Sub
    
        Sub InsertEditForm(plc As PlaceHolder, setUserInput As Boolean)
            'build and add controls to placeholder
            Dim tbl As New Table
            Dim r As TableRow
            Dim c As TableCell
            For Each loc As Location In _Locations
                r = New TableRow
    
                'add cell for location name
                c = New TableCell
                c.Controls.Add(New LiteralControl(loc.Name)) 'add plain text through literal control
                r.Cells.Add(c)
    
                'add cell for each day in the date range for current location
                Dim currentDate As Date = loc.StartDate
                Do Until currentDate > loc.EndDate
                    c = New TableCell
                    Dim chk As New CheckBox
                    chk.ID = "chkLocationDate_" & loc.ID & "_" & currentDate.Ticks
                    chk.Text = currentDate.ToShortDateString
                    If setUserInput Then
                        'set the check state based on current database value
                        Dim pretendValueCameFromDB As Boolean = True
                        chk.Checked = pretendValueCameFromDB
                    End If
                    c.Controls.Add(chk)
                    r.Cells.Add(c)
                    currentDate = currentDate.AddDays(1)
                Loop
    
                tbl.Rows.Add(r)
            Next
            plc.Controls.Add(tbl)
        End Sub
    
        Sub SaveForm(ByVal plc As PlaceHolder)
            Dim ctl As Control
            Dim controlIDParts() As String
            Dim drp As DropDownList
            Dim txt As TextBox
            Dim chk As CheckBox
            For Each ctl In ControlUtils.GetChildControls(plc, GetType(Control))
                If ctl.GetType Is GetType(DropDownList) Then
                    drp = CType(ctl, DropDownList)
                    If drp.ID Like "drpIT_*" Then
                        controlIDParts = drp.ID.Split("_")
                        'update record...
                    End If
                ElseIf ctl.GetType Is GetType(TextBox) Then
                    txt = CType(ctl, TextBox)
                    If txt.ID Like "txtIT_*" Then
                        controlIDParts = txt.ID.Split("_")
                        'update record...
                    End If
                ElseIf ctl.GetType Is GetType(CheckBox) Then
                    chk = CType(ctl, CheckBox)
                    If chk.ID Like "chkLocationDate_*" Then
                        controlIDParts = chk.ID.Split("_")
                        Dim locationID = controlIDParts(1)
                        Dim ticks As Long = Val(controlIDParts(2))
                        Dim d As New Date(ticks)
                        'update record...
                    End If
                End If
            Next
            'commit record changes...
        End Sub
    
    End Class
    

    它在网络表单中的使用(假设你有一个保存按钮和占位符控件):

    Dim _Locations As List(Of Location)
    Dim _LocationsForm As LocationsDynamicForm
    
    Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init
        _Locations = Location.GetSampleLocations()
        _LocationsForm = New LocationsDynamicForm(_Locations)
        _LocationsForm.InsertEditForm(plcLocations, Not Me.IsPostBack)
    End Sub
    
    Protected Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
        _LocationsForm.SaveForm(plcLocations)
    End Sub
    

    解决方案 2 - 将 AddHandler 与动态添加的控件一起使用

    这更接近您想要的,但需要在每个复选框更改时进行回发。添加复选框时,在 BindDays 例程中添加这些行。

    cbAvailible.AutoPostBack = True
    AddHandler cbAvailible.CheckedChanged, AddressOf Insert_Click
    

    您应该修剪子 Insert_Click 签名末尾的 Handles 关键字。当您预先知道将要处理的控件但控件在设计时不存在时,Handles 非常好。

    Private Sub Insert_Click(sender As Object, e As EventArgs)
        ' I want to get here al the checkbox id and insert the values to a databse
        Dim chk As CheckBox = CType(sender, CheckBox)
        Label1.Text = "ID = " & chk.ID & ", Checked = " & chk.Checked
    End Sub
    

    我不确定您是如何在回发中保留您的“LocationData”或将其添加到网页中,但我能够让您的代码的修改版本正常工作。

    【讨论】:

    • 你好,Erik,这对我来说太多了,我是一个初学者。有没有一种简单的方法可以将所有已选中复选框的 cbAvailible.ID 获取到我发布的代码中的 Private Sub Insert_Click Sub?感谢您迄今为止的帮助
    • 我在答案中添加了一个“解决方案 2”,这将是一种让所有复选框在单击时运行 Insert_Click 子的方法。
    • @Erik 非常感谢您的解决方案。这是一个简单的解决方案,到目前为止对我来说效果很好。我将尝试为插入获取其他元素以完成对数据库的更新。如果我完成了我的程序的这一部分,我会告诉你。你对我帮助很大。再次感谢!
    • @Erik,这就是我的解决方案。我已经完成了程序的这一部分。如果检查为真或假,我现在有一个插入和删除 SP 到数据库。我要感谢您的解决方案。您对我的帮助很大!
    【解决方案2】:
    ' Global declaration inside the "Form" class.
    Public Checkboxes as New List(of Checkbox)
    

    每次创建“新复选框”时,将其添加到集合中。

    ...
    Dim cbAvailible As New CheckBox()
    Checkboxes.Add(cbAvailable)
    ...
    

    稍后您可以简单地通过索引引用复选框。

    Dim chk as boolean = Checkboxes(2).checked ' example
    

    另一种选择是使用 Generic.Dictionary 来存储复选框,在这种情况下,每个框都可以有一个“Key”,例如与行或特定内容相关的字符串。

    循环通过复选框。

    For iQ AS integer = 0 to Checkboxes.Count -1
        Dim cb as checkbox = Checkboxes(iq) ' just a way to not use long name during operations.
        Dim checked as boolean = cb.checked ' ... ' do your work here
        ' ...
    Next iQ
    

    您可能需要对所有对象(每行)执行相同操作。

    最后一个索引对于所有这些都应该相同。这也应该与表格对象中的行数相同。

    【讨论】:

    • 您好,达伦,感谢您的解决方案。我看起来像我的解决方案。但是我如何循环遍历所有的复选框,因为我不知道有多少。
    • @Robijn,另一个注意事项,如果您一遍又一遍地重新加载网格,则每次在生成行/对象的循环开始时都必须清除列表。 Checkboxes.Clear
    • 达伦,感谢您的快速回复。我要尝试所有这些。我让你知道。
    • 你好达伦,很抱歉再次问你。但是你能帮我在我发布的代码中将所有勾选的复选框的 cbAvailible.ID 获取到 Private Sub Insert_Click Sub。这样我就可以通过存储过程将它们插入数据库。我在这里疯了
    • 复选框没有“ID”属性。如果您指的是您创建的 Row 的 ID 属性,则通常不会从复选框中获取此属性。您可以从表中的 Row 获取它(无论它存储在哪里)。这是您的动态信息结构需要精心设计的地方,通常不是像您问的那样存储一个复选框,而是存储一个更复杂的数据结构(比如一个自定义结构的列表,其中包含您的所有数据片段) need, checkbox, id, etc...) 那么你只需遍历这个结构,测试你的 checkbox 检查属性,然后构建输出。
    最近更新 更多