DatagridviewComboBoxCell 只用于一个单元格

本文关键字:一个 单元格 只用于 DatagridviewComboBoxCell | 更新日期: 2023-09-27 18:03:53

.NET 3.5 Winforms

我在运行时有一个绑定到数据表的数据网格视图。 有三列。 第三列是唯一可编辑的列。 有时该值是自由文本,有时该值是从组合框中选择的,或者至少是设计。

在我使用以下代码将数据表绑定到数据网格视图后:

    With dgvColumnFilters
        .DataSource = _dtFilter
        .AllowUserToAddRows = False
        .AllowUserToDeleteRows = False
        .Columns(0).Visible = False
        .Columns(0).ReadOnly = True
        .Columns(1).ReadOnly = True
        .Columns(1).Width = 170
        .Columns(1).HeaderCell.Value = "Field"
        .Columns(2).Width = 300
        .Columns(2).HeaderCell.Value = "Filter List to Value"

然后,我继续迭代 dgv 的行。 如果该行需要组合框,我运行如下代码:

            Select Case sOvrType
                Case "NVARCHAR"
                    ' do nothing.  The default is a textbox.
                Case "YESNO" ' an override type to say that I need to ask YES, NO or show ALL Values
                    Dim sTest As String = ""
                    If Not IsDBNull(dgvColumnFilters(2, i).Value) Then
                        sTest = CStr(dgvColumnFilters(2, i).Value)
                    Else
                        sTest = "*"
                    End If
                    dgvColumnFilters(2, i) = New DataGridViewComboBoxCell
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).DataSource = YesNoDataTable()
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).DisplayMember = "display"
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).ValueMember = "value"
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).Value = sTest

即使我单步执行上述代码时,该单元格显示为 DataGridViewComboBoxCell,选择值有效,并且代码没有引发任何错误,我仍然得到一个文本框。

我完全糊涂了。 谁能帮我度过难关? 正如我所说,有些行必须是文本框,而其他行必须是下拉列表组合框。

我错过了什么?

谢谢John。

DatagridviewComboBoxCell 只用于一个单元格

我会跳过将 CBO 列绑定到数据表,尤其是像是、否、全部这样的琐碎列。 这似乎有点混淆了它。 这会将每隔一行的 col 3 "转换"为 CBO:

For n As Integer = 0 To 9
    If n Mod 2 = 0 Then
        ' make a cell object
        Dim cboCell As New DataGridViewComboBoxCell()
        cboCell.DataSource = dtYN
        cboCell.DisplayMember = "display"
        cboCell.ValueMember = "value"
        ' change the dgv after all the props are set
        dgv.Rows(n).Cells(2) = cboCell
    End If
Next

当绑定到数据源时,由于某种原因,默认值仅显示在第一个数据源中。 在设置所有属性之前将其添加到DGV也是问题的一部分。 一旦它被添加到控件中,它就能够开始引发事件。

测试代码:

    Dim dt As New DataTable()
    dt.Columns.Add("Descr")
    dt.Columns.Add("Foo")
    dt.Columns.Add("Bar")

    Dim dtYN As New DataTable         ' fake domain 
    dtYN.Columns.Add("display")
    dtYN.Columns.Add("value")
    dtYN.Rows.Add("Yes", -1)
    dtYN.Rows.Add("No", 0)
    dtYN.Rows.Add("All", 1)
    For j As Integer = 0 To 9
        dt.Rows.Add("this is row ", j.ToString, "")
    Next
    dgv.DataSource = dt
    dgv.Columns(0).Width = 200
    ' the code above goes here

它并没有真正"转换"列,而是添加组件。 这从 3 个 DGV 组件增加到 8 个。 如果你有很多行,它可能会变得很重。

一种更简单的编码和描述方法是使用 List(Of myFilter) ,使用显示过滤器名称/描述的过滤器对象填充 CBO。 当他们选择一个时,请查看cboFilter.SelectedItem.FilterType以了解是否为域列表启用文本框或其他 CBO。 如果是后者,则根据针对cboFilter.SelectedItem.DomainTable的查询填充它。

如果筛选器不是为了立即使用,而是为以后使用而定义,只需将其保存到可能继承自myFilter或公共基类的新List(Of FilterDef)

好的,我想通了这一点,觉得我应该分享完整的答案以使问题清晰易读。

首先,我显式定义了网格的列:

With dgvColumnFilters
        .AutoGenerateColumns = False
        Dim dgvc As DataGridViewColumn = Nothing
        dgvc = New DataGridViewColumn()
        dgvc.Name = "sFilterCol"
        dgvc.Visible = False
        dgvc.Width = 0
        dgvc.ReadOnly = True
        dgvc.CellTemplate = New DataGridViewTextBoxCell()
        dgvc.DataPropertyName = "sFilterCol"
        .Columns.Add(dgvc)
        dgvc = New DataGridViewColumn()
        dgvc.Name = "sFilterName"
        dgvc.Width = 170
        dgvc.HeaderCell.Value = "Field"
        dgvc.CellTemplate = New DataGridViewTextBoxCell()
        dgvc.ReadOnly = True
        dgvc.Visible = True
        dgvc.DataPropertyName = "sFilterName"
        .Columns.Add(dgvc)
        dgvc = New DataGridViewColumn()
        dgvc.Name = "sFilterValue"
        dgvc.Width = 300
        dgvc.HeaderCell.Value = "SearchValue"
        dgvc.CellTemplate = New DataGridViewTextBoxCell()
        dgvc.Visible = True
        dgvc.ReadOnly = False
        dgvc.DataPropertyName = "sFilterValue"
        .Columns.Add(dgvc)
        .DataSource = _dtFilter
        .AllowUserToAddRows = False
        .AllowUserToDeleteRows = False
    End With

这为我设置了每列的固定宽度。 消除自动列生成是一个很大的帮助。

然后,对于每一行,我检查了筛选器值类型,并根据类型为值生成了适当的控件,如下所示:

        With dgvColumnFilters
        Dim sOvrType As String = ""
        For i As Integer = 0 To .Rows.Count - 1
            Dim _sCol As String = .Rows(i).Cells(0).Value.ToString.Trim.ToUpper
            For j As Integer = 0 To _sFilterCol.Count - 1
                If _sFilterCol(j).ToUpper.Trim = _sCol.ToUpper.Trim Then
                    sOvrType = _sFilterOvrType(j)
                    Exit For
                End If
            Next
            Select Case sOvrType
                Case "NVARCHAR"
                    ' do nothing.  The default is a textbox.
                Case "YESNO" ' This is a combobox that lets the user choose YES or NO, and returns "Y" or "N" depending on choice.
                    Dim sTest As String = ""
                    If Not IsDBNull(dgvColumnFilters(2, i).Value) Then
                        sTest = CStr(dgvColumnFilters(2, i).Value)
                    Else
                        sTest = "*"
                    End If
                    dgvColumnFilters.Rows(i).Cells(2).Value = sTest
                    Dim dgvcb As New DataGridViewComboBoxCell
                    dgvcb.AutoComplete = True
                    dgvcb.DataSource = YesNoDataTable()
                    dgvcb.DisplayMember = "display"
                    dgvcb.ValueMember = "value"
                    dgvColumnFilters.Rows(i).Cells(2) = dgvcb
                Case "LOOKUPCOMBO" ' looks up from a dataset generated from a SQL Query.
                    Dim sDisplayMember As String = ""
                    Dim sValueMember As String = ""
                    Dim sLookupTable As String = ""
                    Dim ds As DataSet = LookupComboDataSet(_sFilterCol(i), sLookupTable, sDisplayMember, sValueMember, sErr)
                    If ds Is Nothing Then
                        Throw New Exception("Cannot make lookup combo, error = " & sErr)
                        Exit Sub
                    End If
                    Dim sTest As String = ""
                    If Not IsDBNull(dgvColumnFilters(2, i).Value) Then
                        sTest = CStr(dgvColumnFilters(2, i).Value)
                    Else
                        sTest = "-1"
                    End If
                    dgvColumnFilters(2, i) = New DataGridViewComboBoxCell()
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).AutoComplete = True
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).DataSource = ds.Tables(0)
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).DisplayMember = sDisplayMember
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).ValueMember = sValueMember
                    CType(dgvColumnFilters(2, i), DataGridViewComboBoxCell).Value = sTest
            End Select
        Next
        .Columns(0).Visible = False
    End With

此方案最终生成了正确的输出。

在数据源属性之后设置 DisplayMember 和 ValueMember 属性至关重要。

感谢您的帮助!

John。