As part of a project for some of our customers, I've had to make a userform with a filterable listbox. In this particular scenario, I can't guarantee the order of the columns, so I came up with a general dataview that allows filtering and re-ordering of columns. I'm sharing it as wanting a with multiple columns that can be shared comes up as a common request - this abstracts the hard bits away to provide an easy interface.
At its simplest, with a textbox and a listbox, this is all that's needed:
Private m_oFilterSet As IFilterSet
Private Sub TextBox1_Change()
Me.ListBox1.List = m_oFilterSet.Filter(Me.TextBox1.Text)
End Sub
Private Sub UserForm_Initialize()
Set m_oFilterSet = New FilterSet
m_oFilterSet.Data = Sheets("data").Range("a1").CurrentRegion.Value
Me.ListBox1.List = m_oFilterSet.Filter("")
End Sub
A more complete example would be as follows:
Private Sub UserForm_Initialize()
Set m_oFilterSet = New FilterSet
With m_oFilterSet
'Expects a base-1 2 dimensional array (like a worksheet range)
.Data = Sheets("data").Range("a1").CurrentRegion.Value
'Set the columns that we want to seach on
'This is optional, default is to search all columns
.SearchColumnNamesArray = Array("Company Name", "First Name", "Surname", "Email", "Gender")
'Set the column order, omitted columns are not displayed
'This is optional, default is to display all columns in the order of the source data
.FilterColumnNamesArray = Array("First Name", "Surname", "Company Name", "Email", "Gender", "Price", "Date")
'Formatters take a column name and a string as per the Format() function
'These are applied AFTER the search
.AddFormatter "Price", "£#,###,###0.00"
.AddFormatter "Date", "MMM-yy"
End With
'An empty string returns the full dataset with column filters and formats applied
Me.ListBox1.List = m_oFilterSet.Filter("")
End Sub
Providing the FilterColumnsNamesArray property allows for the re-ordering of columns as well as excluding columns (or including multiple times).
Providing the SearchColumnNamesArray property explicitly sets columns as searchable (excluded columns are ignored), the default is to exclude all columns
Formatters allow the formatting of data in columns within the listbox by column name. This means that only the underlying data is searchable, not the resulting formatted string - the FilterSet is provided with an interface so it would be trivial to provide another implementation to search after formatting. This would actually be more efficient as the formatters could be applied when the data is loaded, rather than as it is displayed.
There may be some bugs in this, it is not thoroughly tested and extracted from a much larger solution - use at your peril!
I've tested this with 10k records and it is performant, however there are various improvements that could be made to increase performance if it is an issue.
Bookmarks