我试图强制用户仅从 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
向
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))