VB.NET datagridview组合框的一对一映射

时间:2013-02-13 20:39:29

标签: vb.net winforms datagridview datagridcomboboxcolumn

我有一个带有两个文本框列和一个组合框列的datagridview。组合框的DataSource绑定到下拉列表值的枚举。 datagridview的DataSource绑定到一个自定义类,其数据类型为string,string和enum。

前两列预先填充了值,在第三列中,用户必须从下拉列表中选择一个值。到目前为止,所有这一切都很出色,除了......

组合框字段应该是一对一的映射,这意味着没有两个组合框应该具有相同的值。我真的不确定如何实现这种行为。是否应从剩余的下拉列表中删除所选值?如果选择的值保留在下拉列表中,并且只选择两个相同的值时会出错?

任何想法以及如何实施这些想法都会有很大帮助。

由于

note 可以多次使用的唯一可接受的值是“无”

enter image description here

2 个答案:

答案 0 :(得分:1)

我有一个想法,可能会从剩余的下拉菜单中删除所选的值。

我有一个名为Runner的类,它与您的示例有类似的设置。

Public Class Runner

    Public Property FirstName As String
    Public Property LastName As String
    Public Property Placement As Result

    Public Sub New(fn As String, ln As String)
        FirstName = fn
        LastName = ln
        Placement = Result.None
    End Sub

End Class

我还有一个名为Result的枚举,它将填入ComboBoxCell

Public Enum Result
    None = 0
    Bronze = 1
    Silver = 2
    Gold = 3
End Enum

当我创建数据对象并将它们绑定到DataGridView时,我这样做(注意 - 放置是一个全局列表(结果),跑者是一个全局列表(Of Runner):

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Placements.Add(Result.None)
    Placements.Add(Result.Bronze)
    Placements.Add(Result.Silver)
    Placements.Add(Result.Gold)
    Runners.Add(New Runner("John", "Smith"))
    Runners.Add(New Runner("Jane", "Doe"))
    Runners.Add(New Runner("Bill", "Jones"))
    Column1.DataPropertyName = "FirstName"
    Column2.DataPropertyName = "LastName"
    Column3.DataPropertyName = "Placement"
    Column3.DataSource = Placements
    DataGridView1.DataSource = Runners
End Sub

现在,只要ComboBoxColumn中的单元格值发生更改,就会从包含枚举的列表中删除新值:

Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
    If (e.RowIndex > -1 And e.ColumnIndex = 2) Then
        Dim currentvalue As Result = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
        If currentvalue <> Result.None Then
            Placements.Remove(currentvalue)
        End If
    End If
End Sub

在更改下拉选项时要小心......按照此Discussion,您必须在DataGridView值更改后立即将ComboBox设置为提交值。我从讨论中得到了答案并做了类似的事情:

Private Sub DataGridView1_CurrentCellDirtyStateChanged(sender As Object, e As EventArgs) Handles DataGridView1.CurrentCellDirtyStateChanged
    Dim col As DataGridViewColumn = DataGridView1.Columns(DataGridView1.CurrentCell.ColumnIndex)
    If col.Name = "Column3" Then
        DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
        Dim selected As DataGridViewCell = DataGridView1.CurrentCell
        DataGridView1.CurrentCell = Nothing //This line and the next one simply hide
        DataGridView1.CurrentCell = selected //an odd display effect that occurs 
                                             //because we remove a value and change the
                                             //selection at the same time
    End If
End Sub

最后,您要处理DataError的{​​{1}}事件并将其留空,以便在从枚举列表中删除值时不会向您发送DataGridView

这可以让你大约90%的方式。更改值时,它不会将项重新添加到列表中。例如,如果我从Gold更改为Silver,则应将Gold添加回列表。您可以找出要处理的事件以获取旧值和新值,并根据枚举值将旧值插回到正确索引的列表中。

答案 1 :(得分:1)

我决定使用DataGridView的CellValidating事件来检查是否多次选择了相同的值。如果是,则在行标题列中显示错误消息。

错误组合框在错误解决之前不会失去焦点。

Private Sub DataGridView1_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating

    Dim headerText As String = DataGridView1.Columns(e.ColumnIndex).HeaderText

    'Abort validation if cell is not in the Mapping column. 
    If Not headerText.Equals("Column Mapping") Then Return

    'Clear error on current row.
    DataGridView1.Rows(e.RowIndex).ErrorText = Nothing
    e.Cancel = False

    Dim newMappingValue As XmlElement = DirectCast([Enum].Parse(GetType(XmlElement), e.FormattedValue), XmlElement)

    ' Abort validation if cell value equal XmlElement.None 
    If newMappingValue.Equals(XmlElement.None) Then Return

    For Each dgvRow As DataGridViewRow In DataGridView1.Rows
        Dim currentMappingValue As XmlElement = dgvRow.Cells.Item(headerText).Value

        If dgvRow.Index <> e.RowIndex Then
            If currentMappingValue.Equals(newMappingValue) Then
                DataGridView1.Rows(e.RowIndex).ErrorText = "Value already selected, please select a different value."
                e.Cancel = True
            End If
        End If
    Next

End Sub

enter image description here