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.
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