Я пытаюсь выполнить автозаполнение с помощью события текстового поля TextChanged, но с VB.NET работаю так медленно.
хотя записей всего 6, что-то не так с моим кодом, подскажите, пожалуйста.
Я прикрепил гифку с примером файла, когда я набрал «KBE», он работал очень медленно, и я выдавал некоторые предложения, пока он не завершился сам, а затем я попробовал набрать «KBT», он тоже работал очень медленно. и придумывайте несколько предложений, пока все не закончится само собой
Спасибо
Public Class Form3
Private iService As New ItemService()
Private bindingSource1 As BindingSource = Nothing
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblcodeproduct.Visible = False
TextBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend
TextBox1.AutoCompleteSource = AutoCompleteSource.CustomSource
TextBox1.AutoCompleteCustomSource.AddRange(iService.GetByCodeProduct().Select(Function(n) n.CodeProduct).ToArray())
End Sub
Private Sub GetItemData2(ByVal iditem As String)
Dim item = iService.GetByCodeProductOrBarcode(iditem)
If item IsNot Nothing Then
If String.Equals(iditem, item.CodeProduct, StringComparison.CurrentCultureIgnoreCase) Then
TextBox1.Text = item.CodeProduct
End If
TextBox2.Text = item.Barcode
Else
TextBox2.Clear()
Return
End If
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If TextBox1.Text = "" Then
lblcodeproduct.Visible = False
ErrorProvider1.SetError(TextBox1, "")
Else
bindingSource1 = New BindingSource With {.DataSource = New BindingList(Of Stock)(CType(iService.GetByCodeProductlike(TextBox1.Text), IList(Of Stock)))}
If bindingSource1.Count > 0 Then
lblcodeproduct.Visible = False
ErrorProvider1.SetError(TextBox1, "")
Else
lblcodeproduct.Visible = True
End If
GetItemData2(TextBox1.Text)
End If
End Sub
End Class
Public Class Stock
Public Property Id() As Integer
Public Property CodeProduct() As String
Public Property Barcode() As String
End Class
Public Class ItemService
Public Function GetOledbConnectionString() As String
Return "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\TRIAL.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 GetByCodeProduct() As IEnumerable(Of Stock)
Dim sql = "SELECT CodeProduct AS CodeProduct FROM Items"
Using _conn = New OleDbConnection(GetOledbConnectionString())
Return _conn.Query(Of Stock)(sql).ToList()
End Using
End Function
Public Function GetByCodeProductlike(ByVal CodeProduct As String) As IEnumerable(Of Stock)
Dim sql = $"SELECT CodeProduct FROM Items WHERE CodeProduct LIKE '%" & CodeProduct & "%'"
Using _conn = New OleDbConnection(GetOledbConnectionString())
Return _conn.Query(Of Stock)(sql).ToList()
End Using
End Function
Public Function GetByCodeProductOrBarcode(ByVal code As String) As Stock
Dim sql = $"SELECT * FROM Items WHERE CodeProduct = '{code}' or Barcode = '{code}'"
Using _conn = New OleDbConnection(GetOledbConnectionString())
Return _conn.Query(Of Stock)(sql).FirstOrDefault()
End Using
End Function
End Class
РЕЗУЛЬТАТ АВТОЗАПОЛНЕНИЕ ТЕКСТА
Не следует запрашивать базу данных при каждом событии TextChanged
. Если вы собираетесь вводить «KBE», какой смысл искать по первым двум символам? Вот что замедляет его. Вам следует запустить/перезапустить Timer
по событию TextChanged
и выполнить поиск по событию Tick
. Вы можете установить Interval
так, чтобы время между нажатиями клавиш не истекало, когда кто-то печатает, а начиналось вскоре после того, как он остановится. Примерно 300–500 миллисекунд должно подойти, но вы можете поэкспериментировать, чтобы увидеть, что работает лучше всего.
@SioGabx, спасибо. за ваш ответ. Я горжусь, что вы пытаетесь найти решение для меня. ссылка это ссылка на образец данных TRIAL.accdb
. tell us what you are using to read your file (is it System.Data.OleDb?).
Вы правы, это System.Data.OleDb
@SioGabx, а для Query function is also missing in the code you shared
я использую Dapper nuget
@SioGabx, извините за беспокойство, у меня есть новый пост, возможно, вы мне поможете. Для этого ссылка
У вас есть рекурсивные вызовы события TextChanged, поскольку GetItemData2 может изменить TextBox1. Я отметил изменения, которые я сделал, с помощью '<<<<<<<<<<<<<<<<<<<<<<<<<.
ОТРЕДАКТИРОВАНО - см. комментарии
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
Static recursive As Boolean = False '<<<<<<<<<<<<<<<<<<<<<<<<<
If recursive Then Exit Sub '<<<<<<<<<<<<<<<<<<<<<<<<<
recursive = True '<<<<<<<<<<<<<<<<<<<<<<<<<
If TextBox1.Text = "" Then
lblcodeproduct.Visible = False
ErrorProvider1.SetError(TextBox1, "")
recursive = False '<<<<<<<<<<<<<<<<<<<<<<<<<
Else
Try '<<<<<<<<<<<<<<<<<<<<<<<<<
bindingSource1 = New BindingSource With {.DataSource = New BindingList(Of Stock)(CType(iService.GetByCodeProductlike(TextBox1.Text), IList(Of Stock)))}
If bindingSource1.Count > 0 Then
lblcodeproduct.Visible = False
ErrorProvider1.SetError(TextBox1, "")
Else
lblcodeproduct.Visible = True
End If
' the following method might change TextBox1
' which results in the .TextChanged event being called again
' the changes mean that second call stops the processing of the .TextChanged event
GetItemData2(TextBox1.Text)
Finally '<<<<<<<<<<<<<<<<<<<<<<<<<
recursive = False '<<<<<<<<<<<<<<<<<<<<<<<<<
End Try
End If
End Sub
Возможно, было бы лучше иметь recursive = False
внутри Finally
, чтобы гарантировать, что это произойдет при выходе по любой причине (и для защиты от неосторожного раннего выхода, который может быть добавлен позже).
@Craig, It might be better to have the recursive = False inside a Finally to ensure that it happens when exiting for any reason (and to protect against a careless early exit that might be added later).
ты имеешь в виду использование try catch finally
@Крейг - Я согласен. Я отредактирую свой ответ.
@user23548857 user23548857 Для этой цели Catch
не нужен, если только вы не хотите что-то с ним сделать — я бы посоветовал по умолчанию не включать Catch
. Цель состоит лишь в том, чтобы Finally
гарантировать, что вам не нужно помнить о включении recursive = False
в каждой точке выхода (и вы застрахованы в случае исключения, которое обрабатывается на более высоком уровне в программе без ее сбоя).
@Craig - за все миллионы лет, что я делал это, я не знал, что попытка может существовать без подвоха. Я видел, если у тебя нет подвоха, значит, у тебя должен быть наконец. СПАСИБО.
Можете ли вы поделиться образцом данных (вашим TRIAL.accdb) и рассказать нам, что вы используете для чтения своего файла (это System.Data.OleDb?). Функция запроса также отсутствует в коде, которым вы поделились.