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

时间:2017-05-26 02:18:58

标签: vb.net datagridview combobox tabcontrol

我的部分代码在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 [深呼吸]让我很困惑!

1 个答案:

答案 0 :(得分:1)

它可能有点hacky但它​​应该做你要求的...希望。我创建了两个List(Of String)个变量。 AllRacers包含所有参赛者...即我们想要出现在组合框中的所有名称,使得该行上没有其他组合框选择了一个项目。这些名称是所有行上的所有组合框最初将包含在可选项列表中的内容。

其他List(Of String) UsedRacers包含当前行中所有选定项目的“组合框”列表。每次更改单元格值并且它是“组合框”列单元格之一时,将清除/更新UsedRacers以反映当前行上添加/更改的所选项目。

更改“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列表中,我们现在可以遍历该行中的每个“组合框”单元格并设置正确的名称列表。为了提供帮助,创建了一个返回DataGridViewComboBoxCell的方法,以便当前UsedRacers列表中的名称不会出现在DataGridViewComboBoxCell的可选名称列表中。

此处唯一的问题是当前已选择项目的单元格。具有所选项目的每个“组合框”单元将唯一地需要在其项目列表中具有其所选项目。要解决此问题,需要检查“combobox”单元格是否包含值。如果“组合框”单元格包含选定值,则该值也包含在UsedRacers列表中。由于THIS单元格是UseRacers列表中的单元格...然后我们需要将此值添加到此单元格项目列表中。否则,我们将无法显示唯一选择。

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

这可以在DataGridViews CellChanged事件中完成。

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(下面)返回DataGridViewComboBoxCell,以便项目组合框列表中的项目不包含UsedRacers中的任何项目名单。因此,需要进行检查(上图)以查看单元格是否已包含值。注意:返回的DataGridViewComboBoxCell将始终包含“空白”空项。这是必要的,允许用户“取消选择”任何当前选择的值,然后使“取消选择”项目可用于其他组合框单元格。

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

我希望这会有所帮助,我猜测有一种更简单的方法可以做到这一点。