VB.NET中文本框多按键处理:退格、Esc键选值越界问题求助
VB.NET TextBox自动补全问题:退格/Esc键未按Enter时允许输入列表外内容的解决指引
我在VB.NET中为TextBox实现了自动补全功能,当前遇到需求:当用户按下退格键或Esc键且未按Enter时,能够输入/选择自动补全列表外的内容。以下是参考@dr.null的建议修改后的代码,恳请提供解决指引。
Imports System.Data.OleDb Public Class Form7 Private connectionString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\dapperdemo.accdb;Persist Security Info=False;" Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = &H10 Then Dim av = Me.AutoValidate Me.AutoValidate = AutoValidate.Disable MyBase.WndProc(m) Me.AutoValidate = av Return End If MyBase.WndProc(m) End Sub Private Sub Form7_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim acsCustomers As New AutoCompleteStringCollection Using dt As DataTable = GetData() acsCustomers.AddRange( dt.AsEnumerable(). Select(Function(r) r.Field(Of String)("CODEPRODUCT")).ToArray()) End Using TextBox1.AutoCompleteMode = AutoCompleteMode.Suggest TextBox1.AutoCompleteSource = AutoCompleteSource.CustomSource TextBox1.AutoCompleteCustomSource = acsCustomers 'AutoValidate = AutoValidate.EnableAllowFocusChange End Sub Private Function GetData() As DataTable Dim conString As String = connectionString Dim query As String = "SELECT CODEPRODUCT FROM Items" Dim dt As New DataTable() Using con As OleDbConnection = New OleDbConnection(conString), cmd As OleDbCommand = New OleDbCommand(query, con), sda As OleDbDataAdapter = New OleDbDataAdapter(cmd) sda.Fill(dt) End Using dt.AcceptChanges() Return dt End Function Private Sub TextBox1_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating Dim product = TextBox1.Text.Trim() Dim products = TextBox1.AutoCompleteCustomSource.Cast(Of String) 'If product.Length > 0 AndAlso products.Any() AndAlso If products.Any() AndAlso Not products.Contains(product, StringComparer.OrdinalIgnoreCase) Then MessageBox.Show("Please Select From List Only...") e.Cancel = True TextBox1.SelectAll() ' Or ' TextBox1.Clear() End If End Sub Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown If e.KeyCode = Keys.Enter Then Me.ValidateChildren() End If End Sub End Class

解决方案
问题核心在于当前的Validating事件会强制验证输入必须在补全列表中,即使用户按退格或Esc键也会触发验证,导致无法输入列表外内容。通过以下修改实现需求:
- 添加一个私有变量标记是否跳过验证:
Private skipValidation As Boolean = False
- 修改
TextBox1_KeyDown事件,处理退格和Esc键,设置跳过验证标记:
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown If e.KeyCode = Keys.Enter Then Me.ValidateChildren() ElseIf e.KeyCode = Keys.Back OrElse e.KeyCode = Keys.Escape Then skipValidation = True ' 若Esc键需要清空内容,可取消下面注释 ' If e.KeyCode = Keys.Escape Then TextBox1.Clear() End If End Sub
- 修改
TextBox1_Validating事件,先判断是否需要跳过验证:
Private Sub TextBox1_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating If skipValidation Then skipValidation = False Return End If Dim product = TextBox1.Text.Trim() Dim products = TextBox1.AutoCompleteCustomSource.Cast(Of String) If product.Length > 0 AndAlso products.Any() AndAlso Not products.Contains(product, StringComparer.OrdinalIgnoreCase) Then MessageBox.Show("请仅从列表中选择...") e.Cancel = True TextBox1.SelectAll() ' Or ' TextBox1.Clear() End If End Sub
修改后的完整代码
Imports System.Data.OleDb Public Class Form7 Private connectionString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\dapperdemo.accdb;Persist Security Info=False;" Private skipValidation As Boolean = False ' 新增标记变量 Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = &H10 Then Dim av = Me.AutoValidate Me.AutoValidate = AutoValidate.Disable MyBase.WndProc(m) Me.AutoValidate = av Return End If MyBase.WndProc(m) End Sub Private Sub Form7_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim acsCustomers As New AutoCompleteStringCollection Using dt As DataTable = GetData() acsCustomers.AddRange( dt.AsEnumerable(). Select(Function(r) r.Field(Of String)("CODEPRODUCT")).ToArray()) End Using TextBox1.AutoCompleteMode = AutoCompleteMode.Suggest TextBox1.AutoCompleteSource = AutoCompleteSource.CustomSource TextBox1.AutoCompleteCustomSource = acsCustomers 'AutoValidate = AutoValidate.EnableAllowFocusChange End Sub Private Function GetData() As DataTable Dim conString As String = connectionString Dim query As String = "SELECT CODEPRODUCT FROM Items" Dim dt As New DataTable() Using con As OleDbConnection = New OleDbConnection(conString), cmd As OleDbCommand = New OleDbCommand(query, con), sda As OleDbDataAdapter = New OleDbDataAdapter(cmd) sda.Fill(dt) End Using dt.AcceptChanges() Return dt End Function Private Sub TextBox1_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating If skipValidation Then skipValidation = False Return End If Dim product = TextBox1.Text.Trim() Dim products = TextBox1.AutoCompleteCustomSource.Cast(Of String) If product.Length > 0 AndAlso products.Any() AndAlso Not products.Contains(product, StringComparer.OrdinalIgnoreCase) Then MessageBox.Show("请仅从列表中选择...") e.Cancel = True TextBox1.SelectAll() ' Or ' TextBox1.Clear() End If End Sub Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown If e.KeyCode = Keys.Enter Then Me.ValidateChildren() ElseIf e.KeyCode = Keys.Back OrElse e.KeyCode = Keys.Escape Then skipValidation = True ' 若Esc键需要清空内容,可取消下面注释 ' If e.KeyCode = Keys.Escape Then TextBox1.Clear() End If End Sub End Class
内容的提问来源于stack exchange,提问作者user22579796
相关产品推荐
相关产品推荐

