实现DataGridView单元格小数输入:点自动转逗号+限制重复分隔符
DataGridView单元格小数输入限制需求及解决方案
需求说明
- 让指定DataGridView单元格支持小数输入,用户输入
.作为分隔符时自动替换为, - 限制不能输入多个分隔符(
.或,),仅允许数字、单个逗号及退格键输入,直接禁止无效输入,不做事后提示
预期输入流程
- 用户输入
4,单元格显示4 - 输入
5,显示45 - 输入
.,自动转为,,显示45, - 再次输入
.或,,无任何输入,仍显示45, - 输入
6,最终显示45,6
已尝试方案
通过EditingControlShowing事件获取单元格的TextBox控件,绑定KeyPress和KeyDown事件尝试将.转为,并限制输入,但未达到预期效果;试过CellValidating、TextChanged等事件也未成功,不想用Double.TryParse做事后提示,希望直接拦截无效输入。
现有代码
Private Sub dgv_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles dgv.EditingControlShowing If TypeOf e.Control Is TextBox AndAlso dgv.CurrentCell.ColumnIndex = 3 Then Dim textBox As TextBox = DirectCast(e.Control, TextBox) AddHandler textBox.KeyPress, AddressOf DataGridViewTextBox_KeyPress AddHandler textBox.KeyDown, AddressOf DataGridViewCell_KeyDown End If End Sub
Private Sub DataGridViewTextBox_KeyPress(sender As Object, e As KeyPressEventArgs) If e.KeyChar = "."c Then e.KeyChar = ","c End If End Sub
Private Sub DataGridViewCell_KeyDown(sender As Object, e As KeyEventArgs) Dim nonNumberEntered As Boolean = False ' Checking keys to write decimal numbers: numbers, comma and delete key for corrections... If e.KeyCode < Keys.D0 OrElse e.KeyCode > Keys.D9 Then If e.KeyCode < Keys.NumPad0 OrElse e.KeyCode > Keys.NumPad9 Then If e.KeyCode <> Keys.Back Then If e.KeyCode <> Keys.Oemcomma Then nonNumberEntered = True End If End If End If End If Dim currentTextBox As TextBox = CType(sender, TextBox) Dim currentText As String = currentTextBox.Text ' Check if the entered text matches the regular expression Dim inputRegex As New Regex("^[0-9]+([,][0-9]+)?$") Dim isValidInput As Boolean = inputRegex.IsMatch(currentText) If Not isValidInput Then nonNumberEntered = True End If If Control.ModifierKeys = Keys.Shift Then nonNumberEntered = True End If End Sub
修正后的解决方案
原代码未主动抑制无效按键,也未处理文本中已存在逗号的场景,以下是调整后的代码:
1. 优化事件绑定(避免重复触发)
每次进入编辑模式时先移除旧的事件处理器,再添加新的,防止重复绑定导致的异常:
Private Sub dgv_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles dgv.EditingControlShowing If TypeOf e.Control Is TextBox AndAlso dgv.CurrentCell.ColumnIndex = 3 Then Dim textBox As TextBox = DirectCast(e.Control, TextBox) ' 移除旧处理器 RemoveHandler textBox.KeyPress, AddressOf DataGridViewTextBox_KeyPress RemoveHandler textBox.KeyDown, AddressOf DataGridViewCell_KeyDown ' 添加新处理器 AddHandler textBox.KeyPress, AddressOf DataGridViewTextBox_KeyPress AddHandler textBox.KeyDown, AddressOf DataGridViewCell_KeyDown End If End Sub
2. 完善KeyPress事件处理
负责字符转换和重复逗号拦截,直接禁止无效输入:
Private Sub DataGridViewTextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Dim textBox As TextBox = DirectCast(sender, TextBox) ' 将点转换为逗号 If e.KeyChar = "."c Then e.KeyChar = ","c End If ' 只允许数字、逗号、退格键 If Not Char.IsDigit(e.KeyChar) AndAlso e.KeyChar <> ","c AndAlso e.KeyChar <> ControlChars.Back Then e.Handled = True Return End If ' 文本中已存在逗号时,禁止再次输入逗号(选中包含逗号的文本替换除外) If e.KeyChar = ","c AndAlso textBox.Text.Contains(",") Then If Not textBox.SelectedText.Contains(",") Then e.Handled = True End If End If End Sub
3. 简化KeyDown事件,拦截无效组合键
通过SuppressKeyPress阻止无效按键生效:
Private Sub DataGridViewCell_KeyDown(sender As Object, e As KeyEventArgs) Dim textBox As TextBox = DirectCast(sender, TextBox) ' 禁止Shift+数字键输入符号(如!@#等) If e.Shift AndAlso (e.KeyCode >= Keys.D0 AndAlso e.KeyCode <= Keys.D9) Then e.SuppressKeyPress = True Return End If ' 定义允许的按键列表 Dim allowedKeys = {Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, Keys.D8, Keys.D9, Keys.NumPad0, Keys.NumPad1, Keys.NumPad2, Keys.NumPad3, Keys.NumPad4, Keys.NumPad5, Keys.NumPad6, Keys.NumPad7, Keys.NumPad8, Keys.NumPad9, Keys.Back, Keys.Oemcomma} ' 拦截不在允许列表中的按键 If Not allowedKeys.Contains(e.KeyCode) Then e.SuppressKeyPress = True End If End Sub
方案说明
KeyPress事件处理字符级别的验证和转换,通过e.Handled = True直接禁止无效输入KeyDown事件拦截功能键和组合键,通过e.SuppressKeyPress = True阻止无效按键生效- 处理了选中文本替换的场景,避免选中包含逗号的文本时无法输入新逗号的问题
- 移除重复事件绑定,防止多次触发导致的异常
内容的提问来源于stack exchange,提问作者Jaime
相关产品推荐
相关产品推荐

