提问人:pball 提问时间:9/25/2021 更新时间:9/29/2021 访问量:508
使用 Enter 键在底行上 VB.net Datagridview 单元格验证
VB.net Datagridview Cell Validation on bottom row with Enter key
问:
我有一个datagridview,我正在使用Cell Validating事件来做一些事情。我遇到了按底行上的 Enter 键不会触发 Cell Validating 事件的问题。这似乎是由于焦点没有转移到不同的单元格。这可以通过向窗体添加 datagridview,添加一些列和至少 1 行,然后添加带有消息提示的 Cell Validating 事件来测试。
有没有办法在按底行的 Enter 键时触发 Cell Validating 事件?
我尝试这样做的原因是因为我有一个组合框列,该列正在修改为允许手动输入文本,并且该代码的一部分使用 Cell Validating 事件将手动输入添加到组合框项目列表中。如果手动输入的文本未添加到组合框项目列表中,则该文本将被清除。因此,如果您手动在底行中键入内容并按回车键,则该文本将消失,因为 Cell Validating 事件未触发。允许手动输入 datagridview 组合框单元格的代码如下。
Private Sub DGV_Risk_EditingControlShowing(ByVal sender As Object, ByVal e As DataGridViewEditingControlShowingEventArgs) Handles DGV_Risk.EditingControlShowing
If (DGV_Risk.CurrentCell.ColumnIndex = 1) Then
Dim c As ComboBox = TryCast(e.Control, ComboBox)
If c IsNot Nothing Then c.DropDownStyle = ComboBoxStyle.DropDown
End If
End Sub
Private Sub DGV_Risk_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles DGV_Risk.CellValidating
MsgBox("here")
If (e.ColumnIndex <> 1) Then Exit Sub
Dim Entry As String = e.FormattedValue
If (Not User.Items.Contains(Entry)) Then
User.Items.Add(Entry)
DGV_Risk.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = Entry
End If
End Sub
答:
这并不能直接解决最初的问题,但实现了我想要的最终目标。根据 JohnG 的建议,datagridview 组合框已恢复为默认的不可编辑状态,并添加了一个单独的按钮,用于向组合框添加值。输入框从用户那里获取一个值,并在简单验证后将该值添加到组合框列表中。
Private Sub Btn_AddNewUser_Click(sender As Object, e As EventArgs) Handles Btn_AddNewUser.Click
Dim NewUser As String = InputBox("Please enter a new user")
If (NewUser <> "") Then
Me.User.Items.Add(NewUser)
End If
End Sub
网格组合框单元格可能非常挑剔,并且会在常规组合框不会的情况下抛出网格。网格组合框因抛出网格而臭名昭著,声称组合框单元格中的组合框项目不“属于”组合框项目列表......并且会“看起来”该项目确实属于项目组合框列表。请参阅本文末尾的在家试用。DataError
DataError
您当前的答案将起作用,但是,在使用此方法之前,您可能需要修复/重新考虑几件事。一个可解决的问题是,没有检查项目组合框中的重复项目,也没有检查多余的添加,如“item1”和“项目1”等。
此外,一个不太可解决的问题是,如果“GRID”使用 .在我的测试中,使用您的代码,需要做更多的工作才能将新项目添加到项目组合框列表中。当网格使用 .在追踪时...您可以在组合框列项目列表中看到新添加的项目;但是,它们“没有”显示。DataSource
DataSource
我猜到这是“为什么”;但是,我真的不在乎,因为 99.999% 的时间......“如果”我使用...“然后”我将使用 .我强烈建议你也这样做。这不仅减少了您必须编写的代码量,而且还可能为您通常必须实现的许多“内置功能”打开了大门......喜欢。。。排序和过滤以及其他有用的功能。同样的理念也适用于 .DataGridView
DataSource
DataSource
DataGridViewComboBoxColumn
因此,在下面的示例中,我同时对网格和组合框列都使用了 a。对于网格,代码使用 simple 作为数据源,因为这是从数据库查询返回的通用数据容器。组合框使用...这是专门为组合框创建的自定义类的简单。我们可以对组合框数据源使用 a,但是在此示例中,我使用了自定义类的列表。造成这种情况的一些原因...DataSource
DataTable
List<ComboItem>
List
DataTable
为了帮助最大程度地减少网格因为“看似”糟糕的项目值而抛出它的机会......我建议为组合框项目制作一个“具体”......即使它们很简单.“应该”使事情以更直观的方式工作。下面的简单示例使用了一个非常简单的 call,专门用于网格的组合框列。DataError
Class
strings
List(Of MyObject)
Class
ComboItem
该类包含一个属性,我们将有一个用作网格组合框列的属性。在大多数情况下,还将使用唯一属性,该属性将成为组合框属性,但是在这种情况下,它不会被使用,并且属性值将用作组合框。该类需要实现的唯一其他方法是允许代码使用 和 方法的 和方法。这个简单的类可能看起来像......String
List(Of ComboItem)
DataSource
int
ID
ValueMember
String
ItemName
DisplayMember
Equals
CompareTo
List
Contains
Sort
Public Class ComboItem : Implements IComparable
Public Property ItemName As String
Public Overrides Function Equals(obj As Object) As Boolean
Dim that = TryCast(obj, ComboItem)
If that IsNot Nothing Then
Return Me.ItemName.Equals(that.ItemName)
End If
Return False
End Function
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
Dim that = CType(obj, ComboItem)
Return Me.ItemName.CompareTo(that.ItemName)
End Function
End Class
请记住...上面的类基本上是对象的“包装器”。String
下面的示例使用了三个全局变量...用作 的 调用。调用 和 用作 的 。最后,为了方便起见,全局公开了它,因为当用户向列表中添加新项目时,我们将更新它。DataTable
GridTable
DataSource
DataGridView
List(Of ComboItem)
ComboItems
DataSource
DatagridViewComboBoxColumn
DataGridViewComboBoxColumn
DataSource
ComboItems
Dim GridTable As DataTable
Dim ComboItems As List(Of ComboItem)
Dim comboCol As DataGridViewComboBoxColumn
为了帮助测试这一点,我们将为网格创建一些测试数据。它将是一个简单的表,其中包含三 (3) 列,分别命名为 和 。组合框列在哪里。由于网格将使用带有实际测试数据...然后,我们需要从中获取测试数据值,以将这些值添加到组合框项目列表中。我们必须在设置网格之前执行此操作,以避免获得网格。String
Col0
Col1
Col2
Col1
DataSouce
Col1
DataSource
DataError
下面是一个返回包含五 (5) 行测试数据的方法。这些值...需要将“ZZZ”、“Cab”、“Bac”和“AAA”添加到组合框项目列表中,以避免错误。GetGridData
DataTable
Col1
Private Function GetGridData() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("Col0", GetType(String))
dt.Columns.Add("Col1", GetType(String))
dt.Columns.Add("Col2", GetType(String))
dt.Rows.Add("C0", "ZZZ", "C2")
dt.Rows.Add("C0", "Cab", "C2")
dt.Rows.Add("C0", "Bac", "C2")
dt.Rows.Add("C0", "Cab", "C2")
dt.Rows.Add("C0", "AAA", "C2")
dt.Rows.Add("", "", "")
Return dt
End Function
接下来,我们需要获取组合框列的数据。如果网格没有数据,则空的将起作用。因此,将创建一个方法,该方法采用 a 和 a 并返回 .这将返回给定数据表中列名等于 的所有 sting 值。此列表将用作组合框列的数据源。将列添加到网格后,我们可以更轻松地知道网格数据源中的所有组合框项也是组合框列中的项项。List(Of ComboItem)
GetComboData
DataTable
curData
String
colName
List(Of ComboItem)
colName
Private Function GetComboData(curData As DataTable, colName As String) As List(Of ComboItem)
Dim items As List(Of ComboItem) = New List(Of ComboItem)
Dim ci As ComboItem
For Each row As DataRow In curData.Rows
ci = New ComboItem()
ci.ItemName = row(colName).ToString()
If (Not String.IsNullOrEmpty(ci.ItemName)) Then
If (Not items.Contains(ci)) Then
items.Add(ci)
End If
End If
Next
Return items
End Function
接下来,我们将(在代码中)设置网格中的列。将有两个和一个.很明显,在调用此方法之前,我们需要调用该方法来填充全局变量。这是相当直接的,每列都设置为给定数据表中的正确列名,我要指出的是,组合框列被赋予了一个,其属性设置为我们类的属性。DataGridViewTextBoxColumns
DataGridViewComboBoxColumn
GetComboData
ComboItems
DataPropertyName
DataSource
DisplayMember
ItemName
ComboItem
Private Sub AddGridColumns()
Dim txtCol As DataGridViewTextBoxColumn = New DataGridViewTextBoxColumn()
txtCol.HeaderText = "Col0"
txtCol.Name = "Col0"
txtCol.DataPropertyName = "Col0"
DGV_Risk.Columns.Add(txtCol)
'combo box column
comboCol = New DataGridViewComboBoxColumn()
comboCol.HeaderText = "Col1"
comboCol.Name = "Col1"
comboCol.DataPropertyName = "Col1"
comboCol.DataSource = ComboItems
comboCol.DisplayMember = "ItemName"
DGV_Risk.Columns.Add(comboCol)
txtCol = New DataGridViewTextBoxColumn()
txtCol.HeaderText = "Col2"
txtCol.Name = "Col2"
txtCol.DataPropertyName = "Col2"
DGV_Risk.Columns.Add(txtCol)
End Sub
如果我们把所有这些放在表单加载事件中......它可能看起来像下面这样......
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GridTable = GetGridData()
ComboItems = GetComboData(GridTable, "Col1")
AddGridColumns()
DGV_Risk.DataSource = GridTable
End Sub
如果我们运行当前代码,组合框应该按预期工作,但是用户无法将项目添加到组合框列项目列表中。为此,我们将添加一个按钮来打开一个新表单以添加项目。它将有一个 和一个 .表单构造函数将被赋予一个 .当表单加载时,将填充给定的组合框项目列表。用户可以在文本框中键入内容以将项目“添加”到列表中。完成后,用户可以单击关闭框返回到原始表单。ListBox
TextBox
Button
List(Of ComboItem)
ListBox
当用户进行添加并关闭对话框窗体时,代码将返回到上一个窗体,并更新组合框列的数据源以反映新项。这个基本形式可能看起来像......
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
listBoxCurItems.DataSource = itemsList
listBoxCurItems.DisplayMember = "ItemName"
End Sub
Dim itemsList As List(Of ComboItem)
Public Sub New(items As List(Of ComboItem))
InitializeComponent()
itemsList = items
End Sub
Private Sub btnAddNewComboText_Click(sender As Object, e As EventArgs) Handles btnAddNewComboText.Click
Dim newValue = TextBox2.Text.Trim()
Dim ci As ComboItem = New ComboItem
ci.ItemName = newValue
If (Not String.IsNullOrEmpty(ci.ItemName)) Then
If (Not itemsList.Contains(ci)) Then
itemsList.Add(ci)
itemsList.Sort()
listBoxCurItems.DataSource = Nothing
listBoxCurItems.DataSource = itemsList
listBoxCurItems.DisplayMember = "ItemName"
Else
MessageBox.Show("Duplicate items not allowed")
End If
Else
MessageBox.Show("Item cannot be an empty string")
End If
End Sub
在此示例中,当用户按下窗体上的按钮时,将调用用于添加新项的窗体,该按钮看起来像...
Private Sub btnAddNewComboText_Click(sender As Object, e As EventArgs) Handles btnAddNewComboText.Click
Dim f3 = New Form3(ComboItems)
F3.ShowDialog()
comboCol.DataSource = Nothing
comboCol.DataSource = ComboItems
End Sub
这应该可以做到。如前所述,这消除了我们之前编写的所有网格事件代码,并且该功能以直观且用户友好的方式工作。
我希望这有帮助并且有意义。
在家试试这个
问“为什么”我使用“包装器”类并不是没有道理的,而一个简单的类可以完成同样的事情。该类还实现了我们需要的 和 接口...所以。。。这似乎没有必要。但是,这个“自己试一试”可以演示为什么使用包装器,也可以演示“为什么”当项目“显然”相同时,您可能会收到无效项目错误。List(Of String)
String
Equals
CompareTo
所以试试这个......创建一个新表单并使用上面相同的代码,然后从列表中更改变量...ComboItems
ComboItem
Dim ComboItems As List(Of ComboItem)
到列表String
Dim ComboItems As List(Of String)
显然,您需要更改代码的其他部分以使用 .此外,由于我们不再使用具有属性的类...我们需要注释掉 因为没有该属性。这将包括对向列表添加项目的表单的更改。这个想法是,我们想使用 a 而不是 a 作为组合框列的 a。String
ComboItem
comboCol.DisplayMember = “ItemName”
String
List(Of String)
List(Of ComboItem)
DataSource
进行更改后,运行代码。在添加项目和更改项目后,它可能/应该按预期工作。然而。。。我几乎可以保证,如果您继续添加新项目,请将组合框更改为这些新项目,并使用组合框进行基本的用户测试......您最终将获得声称该项目不属于项目组合框列表的网格。当我使用“包装器”类时,我从未遇到过此错误。DataError
评论
User