如何强制用户仅从 VB.Net 中的 datagridview 自动完成文本框中选择建议的条目

问题描述 投票:0回答:1

我试图强制用户仅从 VB.Net 中的 datagridview 自动完成文本框中选择建议的条目

还有一个,当正确输入“NameProduct”列时,我希望根据数据库显示“Unit”列

因此,当用户键入时,如果用户在键盘上按退格键和 esc 键,则会出现自动完成功能,那么结果将在列表之外,然后会出现消息框,我希望不允许用户在输入有效输入之前离开列。请指导我

谢谢

Imports System.Data.OleDb
Imports Dapper

Public Class Form1
    Dim ProductsService As New ProductsService()

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub

    Private Sub DataGridView1_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
        Dim column As Integer = DataGridView1.CurrentCell.ColumnIndex
        Dim headerText As String = DataGridView1.Columns(column).HeaderText

        If headerText.Equals("ProductName") Then
            Dim tb As TextBox = TryCast(e.Control, TextBox)

            If tb IsNot Nothing Then
                tb.AutoCompleteMode = AutoCompleteMode.Suggest
                tb.AutoCompleteSource = AutoCompleteSource.CustomSource
                tb.AutoCompleteCustomSource.AddRange(ProductsService.GetByProductname().Select(Function(n) n.ProductName).ToArray())
            End If
        Else
            Dim tb As TextBox = TryCast(e.Control, TextBox)
            If tb IsNot Nothing Then
                tb.AutoCompleteMode = AutoCompleteMode.None
            End If
        End If

    End Sub
End Class
Public Class Products
    Public Property Id() As Integer
    Public Property ProductName() As String

    Public Property Unit() As String

End Class
Public Class ProductsService
    Public Function GetOledbConnectionString() As String
        Return "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\test03092024.accdb;Persist Security Info=False;"
    End Function
    Private ReadOnly _conn As OleDbConnection
    Private _connectionString As String = GetOledbConnectionString()
    Public Sub New()
        _conn = New OleDbConnection(_connectionString)
    End Sub
    Public Function GetByProductname() As IEnumerable(Of Products)
        Dim sql = "SELECT ProductName AS ProductName FROM [Products]"
        Using _conn = New OleDbConnection(GetOledbConnectionString())
            Return _conn.Query(Of Products)(sql).ToList()
        End Using
    End Function
End Class

样本表

Products

ProductName Unit
Absecon         Cup1
Abstracta   Pcs2
Abundantia  Cup3
Academia    Pcs4
Acadiau         Cup5
Acamas          Pcs6
Ackerman    Cup7
Ackley          Pcs8
Ackworth    Cup9
Acomita         Pcs10
Aconcagua   Cup11
Acton           Pcs12
Acushnet    Cup13
Acworth         Pcs14
Ada         Cup15
Ada         Pcs16
Adair           Cup17
Adairs          Pcs18
Adair           Cup19
Adak            Pcs20
Adalberta   Cup21
Adamkrafft  Pcs22
Adams           Cup23
vb.net winforms datagridview autocomplete textbox
1个回答
0
投票

ProductsService
类添加一个返回不同
IEnumerable<T>
元素的方法,其中
T
是封装表示所需数据库字段的属性的模型。如果数据库表不包含重复产品,请从
DISTINCT
语句中删除
SELECT
谓词。

Public Class ProductsService
    Private Shared Function GetOledbConnectionString() As String
        Return "Provider=Microsoft.ACE.OLEDB.12.0;
                Data Source=|DataDirectory|\test03092024.accdb;
                Persist Security Info=False;"
    End Function

    ' ...

    Friend Shared Function GetDistinctProducts() As IEnumerable(Of Product)
        Dim sql = "SELECT DISTINCT ProductName, Unit 
                   FROM Products 
                   ORDER BY ProductName"
        Using _conn = New OleDbConnection(GetOledbConnectionString())
            Return _conn.Query(Of Product)(sql)
        End Using
    End Function
End Class

Public Class Product
    Public Property ProductName As String
    Public Property Unit As String

    Public Overrides Function ToString() As String
        Return $"{ProductName} {Unit}"
    End Function
End Class

重写 Form 的

OnLoad
方法来设置网格。绑定一个空的
BindingList<Product>
,并初始化一个类型为
Dictionary<Of String, String)
的类字段,其中
Keys
是产品,
Values
是相应的单位。该词典用于:

  • 使用

    DataGridViewTextBoxEditingControl.AutoCompleteCustomSource
    事件中的
    Keys
    (产品)填充空的
    DataGridView.EditingControlShowing
    字符串集合。

  • 验证

    ProductName
    事件中的
    DataGridView.CellValidating
    单元格。
    Keys
    必须包含要推送到底层数据源的用户输入。否则,单元格将在编辑模式下保持焦点,并且当前行显示错误图标。

  • Unit
    事件中设置有效产品对应的
    DataGridView.CellValidated

Public Class Form1
    Private dictProducts As Dictionary(Of String, String)

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)

        dictProducts = ProductsService.GetDistinctProducts().
            ToDictionary(Function(p) p.ProductName, Function(p) p.Unit)

        DataGridView1.DataSource = New BindingList(Of Product)
        DataGridView1.Columns("Unit").ReadOnly = True
    End Sub

    Private Sub DataGridView1_EditingControlShowing(
        sender As Object,
        e As DataGridViewEditingControlShowingEventArgs) Handles _
        DataGridView1.EditingControlShowing
        If TypeOf e.Control Is TextBox Then
            Dim dgv = DirectCast(sender, DataGridView)
            Dim tb = DirectCast(e.Control, TextBox)

            If dgv.CurrentCell.ColumnIndex = dgv.Columns("ProductName").Index Then
                If tb.AutoCompleteCustomSource.Count = 0 Then
                    tb.AutoCompleteSource = AutoCompleteSource.CustomSource
                    tb.AutoCompleteCustomSource.AddRange(dictProducts.Keys.ToArray())
                End If
                tb.AutoCompleteMode = AutoCompleteMode.Suggest
            Else
                tb.AutoCompleteMode = AutoCompleteMode.None
            End If
        End If
    End Sub

    Private Sub DataGridView1_CellValidating(
        sender As Object,
        e As DataGridViewCellValidatingEventArgs) _
        Handles DataGridView1.CellValidating
        Dim dgv = DirectCast(sender, DataGridView)

        If e.ColumnIndex = dgv.Columns("ProductName").Index AndAlso
           e.RowIndex <> dgv.NewRowIndex Then
            Dim key = e.FormattedValue.ToString()

            If String.IsNullOrEmpty(key) OrElse
               Not dictProducts.ContainsKey(key) Then
                dgv.Rows(e.RowIndex).ErrorText = "Invalid Product!"
                e.Cancel = True
            End If
        End If
    End Sub

    Private Sub DataGridView1_CellValidated(
        sender As Object,
        e As DataGridViewCellEventArgs) Handles DataGridView1.CellValidated
        Dim dgv = DirectCast(sender, DataGridView)

        If e.ColumnIndex = dgv.Columns("ProductName").Index Then
            Dim boundItem = TryCast(dgv.Rows(e.RowIndex).DataBoundItem, Product)
            If boundItem IsNot Nothing Then
                Dim value = dictProducts(boundItem.ProductName)
                If value <> boundItem.Unit Then
                    boundItem.Unit = value
                    dgv.UpdateCellValue(dgv.Columns("Unit").Index, e.RowIndex)
                End If
                dgv.Rows(e.RowIndex).ErrorText = Nothing
            End If
        End If
    End Sub
End Class

获取底层数据源。

Dim src = DirectCast(DataGridView1.DataSource, BindingList(Of Product))
© www.soinside.com 2019 - 2024. All rights reserved.