VB程序设置DataGridViewCellValidatingEventArgs.Cancel=True引发控件事件异常
问题原因与解决方案
这个问题我之前遇到过,根源在于当你在CellValidating事件中设置e.Cancel = True时,DataGridView会强制保持编辑状态,导致Windows的消息路由出现异常,最终让其他控件的点击事件被劫持,反复触发CellValidating而不是执行它们原本的功能。
具体原因解析
当DataGridView处于编辑模式时,如果你通过e.Cancel = True阻止了单元格编辑的结束,控件会牢牢抓住焦点,不允许用户切换到其他控件。这时候,用户点击其他按钮或窗体控件时,Windows会先尝试让DataGridView完成编辑(再次触发CellValidating),但因为你一直返回Cancel,这个过程会进入循环——看起来是控件没反应,实际上每次点击都在重复执行你的验证逻辑。
另外你的原代码还有个细节问题:一旦找到重复值就立刻设置e.Cancel = True,但循环仍会继续执行,这会导致多次触发Cancel逻辑,进一步加重消息阻塞的问题。
修复后的代码示例
Private Sub MyForm_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) Handles myDGV.CellValidating Dim dgv As DataGridView = CType(sender, DataGridView) Dim isDuplicate As Boolean = False Dim inputValue As String = e.FormattedValue.ToString().Trim() Select Case dgv.Columns(e.ColumnIndex).Name Case "uniqueColumn" ' 先排除空值,避免无意义的比较 If String.IsNullOrEmpty(inputValue) Then dgv.Rows(e.RowIndex).ErrorText = String.Empty Exit Select End If ' 检查重复值,找到后立即退出循环 For i As Integer = 0 To dgv.RowCount - 1 ' 排除当前行和新行(默认的空白新增行) If i <> e.RowIndex AndAlso Not dgv.Rows(i).IsNewRow Then Dim existingValue As String = dgv.Rows(i).Cells(e.ColumnIndex).FormattedValue.ToString().Trim() If inputValue = existingValue Then isDuplicate = True Exit For End If End If Next If isDuplicate Then e.Cancel = True dgv.ShowRowErrors = True dgv.Rows(e.RowIndex).ErrorText = "Data in the unique column must be unique" ' 确保焦点停留在当前单元格,避免消息混乱 dgv.CurrentCell = dgv.Rows(e.RowIndex).Cells(e.ColumnIndex) Else ' 验证通过时清除错误提示 dgv.Rows(e.RowIndex).ErrorText = String.Empty End If Case Else ' 其他列不做验证 End Select End Sub
额外注意事项
- 不要在CellValidating事件中执行耗时操作,否则会让消息阻塞的问题更严重;
- 如果需要允许用户在验证失败时切换控件,可以考虑在
CellEndEdit事件中处理,或者手动调用dgv.CancelEdit()放弃当前编辑(但会丢失用户输入); - 检查是否有其他事件(比如
LostFocus)的代码和CellValidating逻辑冲突,避免双重触发验证。
内容的提问来源于stack exchange,提问作者aphid
相关产品推荐
相关产品推荐

