DatagridviewComboBoxCell仅适用于一个单元格

时间:2014-05-17 15:01:01

标签: c# vb.net winforms datagridview

.NET 3.5 Winforms

我有一个datagridview绑定到RUNTIME的数据表。有三列。第三列是唯一可编辑的列。有时值是自由文本,有时值是组合框中的选择,或者至少是设计。

使用以下代码将数据表绑定到Datagridview之后:

    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,选择值也有效,代码不会抛出任何错误。

我完全糊涂了。任何人都可以帮我解决这个问题吗?正如我所说,有些行必须是文本框,其他行是下拉列表组合框。

我错过了什么?

谢谢, 约翰。

2 个答案:

答案 0 :(得分:0)

我会跳过将CBO列绑定到数据表,尤其是像Yes,No,All这样的简单数据库。这似乎有点混淆了。这会将每个其他行的第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的查询填充它。

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

答案 1 :(得分:0)

好的,我想出来了,觉得我应该分享完整的答案,使问题清晰可读。

首先,我明确定义了网格的列:

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

这种情况最终产生了正确的输出。

在DataSource属性之后设置DisplayMember和ValueMember属性至关重要。

感谢您的帮助!

约翰。