.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,选择值也有效,代码不会抛出任何错误。
我完全糊涂了。任何人都可以帮我解决这个问题吗?正如我所说,有些行必须是文本框,其他行是下拉列表组合框。
我错过了什么?
谢谢, 约翰。
答案 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属性至关重要。
感谢您的帮助!
约翰。