TextChanged event update ListBox fastest approach

I am using a DesktopTextField where as the user types, the filtered results list is shown in a ListBox. However, this is very slow as the original dataset includes thousands of rows of data.
I have tried lazy loading the data into the ListBox, however it still needs to query the database each time the TextChanged event is fired, which appears to be the slowest part of it.

I know there may be alternative UI with better performance, but assuming I want the ListBox to update on TextChange, what is the fastest approach to querying the database and refreshing the ListBox?

An approach I have used is to not run the query/update the listbox until the user has typed at least 3 characters. That results in much smaller result sets.

Another approach would be to use a timer to update the listbox and only update it when the user pauses their typing for a short time. Set the timer period to something that feels right to you, and reset the timer in TextChanged. That allows the user to type quickly without being slowed down by the listbox update, and then see the results if they pause or slow down.

2 Likes

Thanks, I really like the timer idea - it’s quite creative. I’ll give it a go, perhaps in combination with a minimum character count.

I have two forms of filtering: one for the ListBox as it currently appears and another where you can add field filters.

The first form of raw text searching is very fast with no database lookup. If they press Return in an empty Search field, it queries the database afresh, allowing them to perform raw text drill-down searches anew. The second technique requires the user to think, so it is used less.

My code works cross-platform and with GraffitiGrids, so you can ignore the bits that are not relevant.

Here is the raw searching code:

Protected Sub doSearchListBoxRemoveRows(myListBox As Object, searchText As String)
  If searchText = "" Or myListBox = Nil Then Return
  
'returns a ListBox as a tab-delimited array
  Var TableData() As String = CommonWindow.getListBoxToArray(myListBox, CommonStrings.Tab)
  
  If TableData.LastIndex < 0 Then Return
  
  'turn all search text curly quotes to plain for searching
  searchText = searchText.ReplaceAll("‘", "'")
  searchText = searchText.ReplaceAll("’", "'")
  searchText = searchText.ReplaceAll("“", "'")
  searchText = searchText.ReplaceAll("”", "'")
  
  For tempInt As Integer = TableData.LastIndex DownTo 0
    TableData(tempInt) = TableData(tempInt).ReplaceAll("‘", "'")
    TableData(tempInt) = TableData(tempInt).ReplaceAll("’", "'")
    TableData(tempInt) = TableData(tempInt).ReplaceAll("“", "'")
    TableData(tempInt) = TableData(tempInt).ReplaceAll("”", "'")
    
    If TableData(tempInt).IndexOf(0, searchText) < 0 Then 'can't find the searchText?
      #If TargetDesktop Then
        If myListBox IsA DesktopListBox Then
          DesktopListBox(myListBox).RemoveRowAt(tempInt)
          
        ElseIf myListBox IsA GraffitiGrid Then
          GraffitiGrid(myListBox).RemoveRow(tempInt)
        End If
        
      #ElseIf TargetWeb Then
        If myListBox IsA WebListbox Then
          WebListbox(myListBox).RemoveRowAt(tempInt)
          
        ElseIf myListBox IsA GraffitiGrid Then
          GraffitiGrid(myListBox).RemoveRow(tempInt)
        End If
        
      #ElseIf TargetiOS Then
        If myListBox IsA ClassTableData Then
          ClassTableData(myListBox).TableRowData.RemoveAt(tempInt)
        End If
      #EndIf
    End If
  Next
  doListBoxSetColumnWidths(myListBox) 'reset the proportional column widths
End Sub

Also, make sure that whatever field you’re querying in the database is indexed. That should make your search a lot faster.

2 Likes

Yes, yes, yes and yes! This point cannot be emphasized strongly enough!