You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

Form7界面截图


解决方案

问题核心在于当前的Validating事件会强制验证输入必须在补全列表中,即使用户按退格或Esc键也会触发验证,导致无法输入列表外内容。通过以下修改实现需求:

  1. 添加一个私有变量标记是否跳过验证:
Private skipValidation As Boolean = False
  1. 修改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
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:02:09