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。
我会跳过将 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。