.NET полный текст автозаполнения в выпадающем списке. Есть ли способ переопределения списочных элементов с точки зрения производительности? - PullRequest
2 голосов
/ 02 ноября 2011

Я изо всех сил стараюсь удовлетворить спрос моих руководителей. Я действительно надеюсь, что кто-то может дать какой-то совет. В основном в нашем проекте есть места, где есть большой выбор опций. Самый конкретный пример - выбор города в мире. Предметов сотни тысяч. Используя стандартные элементы управления и свойства winforms, можно быстро найти список. Проблема в том, что мы используем объединение названия города и района для всех элементов. По существу, автозаполнение PREFIX работает, но не работает по мере необходимости. Задача состоит в том, чтобы фильтровать и отображать элементы по любой заданной строке в любой части элемента. По существу, полный текст поиска в выпадающем списке. Есть ли у кого-нибудь идеи относительно переключения источников автозаполнения во время выполнения относительно быстро и обработки события предложить / предложитьtappend? Также проект находится на VB.NET, хотя любая форма .NET-рекомендаций будет чрезвычайно полезна.

Спасибо!

ОБНОВЛЕНИЕ: последняя попытка с использованием предложения tims_tech с некоторыми незначительными изменениями.

Imports System.Data
Public Class Form1
Private _ErrorText As String
Private _CommandExecuted As Boolean

Private m_fOkToUpdateAutoComplete As Boolean
Private m_sLastSearchedFor As String = ""

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Call Me.SetStatusText("Loading...")
    Me._ErrorText = ""
    Me.Cities.Clear()
    Me.BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Try
        Me._CommandExecuted = True
        Me.Ara_airportsTableAdapter.Fill(Me.Cities.ara_airports)
    Catch ex As Exception
        _ErrorText = ex.Message
    End Try
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    If Me._ErrorText = "" Then
        Me.SetStatusText(Me.Cities.ara_airports.Count & " Records loaded")
    Else
        Me.SetStatusText(Me._ErrorText)
    End If
    Me.BindingSource.ResetBindings(False)
End Sub

Private Sub SetStatusText(ByVal sText As String)
    Me.Text = sText
End Sub

Private Sub cboPort_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles cboPort.KeyDown
    Try
        If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Down Then
            m_fOkToUpdateAutoComplete = False
        Else
            m_fOkToUpdateAutoComplete = True
        End If
    Catch theException As Exception
        ' ...
    End Try
End Sub

Private Sub cboPort_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboPort.KeyUp
    Try
        If m_fOkToUpdateAutoComplete Then
            With cboPort
                If .Text.Length >= 2 Then
                    Dim cSuggestions As IList
                    Dim sError As String = ""

                    m_sLastSearchedFor = .Text

                    cSuggestions = GetSuggestions(m_sLastSearchedFor)
                    .DataSource = Nothing
                    If cSuggestions IsNot Nothing Then
                        .BindingContext = New BindingContext
                        .DisplayMember = "CName"
                        .ValueMember = "id"
                        .DataSource = New BindingSource(cSuggestions, Nothing)

                        System.Threading.Thread.Sleep(10)
                        System.Windows.Forms.Application.DoEvents()
                        .DroppedDown = True
                        .Text = m_sLastSearchedFor
                        If .Text.Length > 0 Then .SelectionStart = .Text.Length
                    End If
                End If
            End With
        End If
    Catch theException As Exception
        ' ...
    End Try
End Sub

Private Function GetSuggestions(ByVal searchFor As String) As IList
    BindingSource.Filter = "CName LIKE '%" & searchFor & "%'"
    Return BindingSource.List
End Function

End Class

1 Ответ

3 голосов
/ 02 ноября 2011

Способ решения этой проблемы с очень большими наборами данных (полный набор информации о препарате):

1) Обработка события TextChanged комбо

2) В этом событии получитесписок предложений, которые соответствуют текущему вводу пользователя из базы данных.Мы используем возможности поиска в базе данных для поиска совпадений в любом месте строки.

3) Когда предложения найдены, свяжите их с полем со списком

4) Подождите немного (500 мс)чтобы позволить пользовательскому интерфейсу наверстать упущенное (мы используем комбинацию System.Threading.Thread.Sleep и System.Windows.Format.Application.DoEvents ()).

Несколько замечаний по этому подходу:

1) Ничто не привязано к списку при первом открытии формы

2) Мы ждем, пока пользователь введет хотя бы 4 символа, прежде чем мы начнем поиск, чтобы уменьшить попадание в БД и улучшитьпользовательский опыт (например, вы не хотите показывать все совпадения для A).

Обновление с кодом для отображения полного решения:

Вот некоторыедополнительные примечания и код, чтобы показать фактический процесс.

ComboBox должен быть настроен со всеми свойствами, установленными в их значения по умолчанию, за исключением:

AutoCompleteMode = SuggestAppend
PreferredDropDownSize = 0, 0

Вот код, который мы используем для нашей конкретной ситуации (поиск первых четырехchars) с заполнителем для извлечения и назначения данных:

Private m_fOkToUpdateAutoComplete As Boolean
Private m_sLastSearchedFor As String = ""

Private Sub cboName_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles cboName.KeyDown
    Try
        ' Catch up and down arrows, and don't change text box if these keys are pressed.
        If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Down Then
            m_fOkToUpdateAutoComplete = False
        Else
            m_fOkToUpdateAutoComplete = True
        End If
    Catch theException As Exception
        ' Do something with the error
    End Try
End Sub

Private Sub cboName_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboName.TextChanged
    Try
        If m_fOkToUpdateAutoComplete Then
            With cboName
                If .Text.Length >= 4 Then
                    ' Only do a search when the first 4 characters have changed
                    If Not .Text.Substring(0, 4).Equals(m_sLastSearchedFor, StringComparison.InvariantCultureIgnoreCase) Then
                        Dim cSuggestions As IEnumerable
                        Dim sError As String = ""

                        ' Record the last 4 characters we searched for
                        m_sLastSearchedFor = .Text.Substring(0, 4)

                        ' And search for those
                        cSuggestions = GetSomeSuggestions(m_sLastSearchedFor) ' Your code here
                        .DataSource = Nothing
                        If cSuggestions IsNot Nothing Then
                            ' Because this can use the same data source as the list, ensure that
                            ' the bindingcontexts are different so that the lists are not tied to each other
                            .BindingContext = New BindingContext

                            .DataSource = cSuggestions

                            ' Let the UI process the results
                            System.Threading.Thread.Sleep(10)
                            System.Windows.Forms.Application.DoEvents()
                        End If
                    End If
                Else
                    If Not String.IsNullOrEmpty(m_sLastSearchedFor) Then
                        ' Clear the last searched for text
                        m_sLastSearchedFor = ""
                        cboName.DataSource = Nothing
                    End If
                End If
            End With
        End If
    Catch theException As Exception
        ' Do something with the error
    End Try
End Sub
...