VB.NET 如何将事件处理程序添加到位于以编程方式创建的控件中的 ComboBoxColumn?

VB.NET How to add Event Handler to ComboBoxColumn located in programmatically created controls?

我的部分代码在 tabcontrol 中创建了一个选项卡,然后用一个 datagridview 填充它,其中包含几列 DataGridViewComboBoxColumn。

看起来像这样:

Private Sub NewTabPage()
    Dim TabPageCount As Integer = RacerOrderTAB.TabPages.Count
    RacerOrderTAB.TabPages.Add(TeamNames(TabPageCount)) 'teamnames() is an array of team names

    Dim CurrentTabPage = RacerOrderTAB.TabPages(TabPageCount)
    Dim GridToAdd As New DataGridView

    GridToAdd.Size = CurrentTabPage.Size
    GridToAdd.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
    GridToAdd.Location = New Point(CurrentTabPage.Location.X, CurrentTabPage.Location.Y)
    GridToAdd.Columns.Add("ShiftCOL", "Shift Name")
    GridToAdd.Name = "grid_" & CurrentTabPage.Text

    For y As Integer = 1 To ShiftSetup.racerspershift 'add extra column for each racer in shift

        Dim cmb As New DataGridViewComboBoxColumn

        cmb.HeaderText = "Racer" & y
        cmb.Name = "Racer_" & y
        cmb.MaxDropDownItems = AmountOfRacers
        cmb.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton

        GridToAdd.Columns.Add(cmb)
    Next

    RacerOrderTAB.TabPages(TabPageCount).Controls.Add(GridToAdd)
End Sub

但是我一直难以为组合框添加事件处理程序。我想要发生的是,当单击并打开组合框时,我用我想要的项目填充它。 我设法通过添加模糊地让它工作:

AddHandler GridToAdd.EditingControlShowing, AddressOf <sub name> 

但后来无法确定单击了哪个组合框,以及如何填充它。在下拉列表出现之前,它也需要点击四次。我只是有点困惑。

感谢您的建议;这些 DataGridViewComboBoxColumns [深呼吸] 让我很困惑!

它可能有点老套,但它应该可以满足您的要求……希望如此。我创建了两个 List(Of String) 变量。 AllRacers 包含所有赛车手……即我们希望出现在组合框中的所有名称,以便该行上没有其他组合框选择了一个项目。这些名称是所有行上的所有组合框最初包含在可选项目列表中的名称。

另一个 List(Of String) UsedRacers 包含当前行上所有已选择项目的“组合框”的列表。每次更改单元格值并且它是“组合框”列单元格之一时,UsedRacers 是 cleared/updated 以反映当前行上的 added/changed 所选项目。

当“comboBox”单元格值改变时,SetUsedRacersForRow被调用…

Private Sub SetUsedRacersForRow(rowIndex As Int16)
  UsedRacers.Clear()
  Dim curValue = ""
  For i = 1 To racersPerShift
    If (Not (dgvRacers.Rows(rowIndex).Cells(i).Value Is Nothing)) Then
      curValue = dgvRacers.Rows(rowIndex).Cells(i).Value.ToString()
      If (Not (String.IsNullOrEmpty(curValue))) Then
        UsedRacers.Add(curValue)
      End If
    End If
  Next
End Sub

上面的代码遍历给定行中的所有“组合框”单元格,如果“组合框”单元格选择了某些内容,则所选值将添加到 UsedRacers 列表中。

既然该行中所有“组合框”的选定项目都在 UsedRacers 列表中,我们现在可以遍历该行中的每个“组合框”单元格并设置正确的名称列表。为了提供帮助,创建了一个 returns 和 DataGridViewComboBoxCell 的方法,这样当前 UsedRacers 列表中的名称将不会出现在 DataGridViewComboBoxCell 的可选名称列表中。

这里唯一的问题是当前选择了项目的单元格。每个选择了项目的“组合框”单元格都需要在其项目列表中包含其选择的项目。为了解决这个问题,需要检查“组合框”单元格是否包含值。如果“组合框”单元格包含选定值,则该值也包含在 UsedRacers 列表中。由于此单元格是 UseRacers 列表中的单元格……因此我们需要将此值添加到此单元格项目列表中。否则,我们将无法显示唯一选择。

为了保持 UsedRacers 列表的一致性,我们需要将此项目直接添加到单个“组合框”单元格中,而不是删除或更改 UsedRacers 列表,因为这将用于另一个“组合框”单元格。换句话说......无论在组合框中选择什么值,我们都需要确保它是“组合框”可选项目列表中的项目之一。我希望这是有道理的。

这些都可以在DataGridViewsCellChanged活动中完成。

Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvRacers.CellValueChanged
  If (e.ColumnIndex >= 1 And e.ColumnIndex <= racersPerShift) Then
    SetUsedRacersForRow(e.RowIndex)
    For i = 1 To racersPerShift
      Dim newCell As DataGridViewComboBoxCell = GetCurrentComboBoxCell()
      If (Not (dgvRacers.Rows(e.RowIndex).Cells(i).Value Is Nothing)) Then
        Dim curValue = dgvRacers.Rows(e.RowIndex).Cells(i).Value.ToString()
        newCell.Items.Add(curValue)
        newCell.Value = curValue
      End If
      dgvRacers.Rows(e.RowIndex).Cells(i) = newCell
    Next
  End If
End Sub

在上面的代码中,一个方法GetCurrentComboBoxCell(下面)returns一个DataGridViewComboBoxCell使得组合框项目列表中的项目不包含任何项目UsedRacers 列表。因此,需要检查(上图)以查看单元格是否已包含值。注意:返回的 DataGridViewComboBoxCell 将始终包含一个“空白”的空项目。这是必要的,以允许用户“De-Select”任何当前选择的值,然后使“De-Selected”项目可用于其他组合框单元格。

Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
  Dim newComboCell = New DataGridViewComboBoxCell()
  newComboCell.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
  newComboCell.FlatStyle = FlatStyle.Flat
  newComboCell.Items.Add("")
  For Each curRacer In AllRacers
    If (Not UsedRacers.Contains(curRacer)) Then
      newComboCell.Items.Add(curRacer)
    End If
  Next
  Return newComboCell
End Function

最后,把所有这些放在一起……

Dim racersInShift = 3
Dim AllRacers As List(Of String) = New List(Of String) From {"John", "Bobby", "Trent", "Josh", "Chapman", "Henry", "George", "Marvin"}
'Dim racersPerShift As Int16 = AllRacers.Count '<-- should be MAX value
Dim racersPerShift As Int16 = 4
Dim UsedRacers = New List(Of String)

Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  BuildGrid()
End Sub

Private Sub BuildGrid()
  dgvRacers.Size = New Size(800, 200)
  dgvRacers.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
  'dgvRacers.Location = New Point(50, 200)
  dgvRacers.Columns.Add("ShiftCOL", "Shift Name")
  dgvRacers.Name = "RacersDGV"
  dgvRacers.EditMode = DataGridViewEditMode.EditOnEnter
  dgvRacers.AllowUserToAddRows = False
  AddRacerColumns()
  AddRacerRows()
End Sub

Private Sub AddRacerColumns()
  Dim newColumn As DataGridViewComboBoxColumn
  For i As Integer = 1 To racersPerShift
    newColumn = GetNewComboBoxColumn("Racer" & i, "Racer " & i)
    dgvRacers.Columns.Add(newColumn)
  Next
End Sub

Private Sub AddRacerRows()
  For i As Integer = 1 To racersInShift
    Dim row As New DataGridViewRow
    dgvRacers.Rows.Add(row)
  Next
End Sub

Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) 
   ‘See code above
End Sub

Private Sub SetUsedRacersForRow(rowIndex As Int16)
  ‘See code above
End Sub

Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
  ‘See code above
End Function

‘Lastly a method to set a whole `DataGridviewComboBoxColumn` which is used to initialize all the combo box columns

Public Function GetNewComboBoxColumn(colName As String, colHeader As String) As DataGridViewComboBoxColumn
  Dim newComboCol = New DataGridViewComboBoxColumn()
  newComboCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
  newComboCol.FlatStyle = FlatStyle.Flat
  newComboCol.Items.Add("")
  newComboCol.HeaderText = colHeader
  newComboCol.Name = colName
  For Each curRacer In AllRacers
    newComboCol.Items.Add(curRacer)
  Next
  Return newComboCol
End Function

希望这对您有所帮助,我想有更简单的方法可以做到这一点。