[英]VB.NET Listview Multiple Column Filter
我的目標是使用多個文本框開發搜索。 我有五個列(ArticleNo,Description,PartNum,Manufacturer和Cost),每個列都有一個文本框。
我使用以下方法跟蹤原始列表項:
Private originalListItems As New List(Of ListViewItem)
這充滿了所有項目(超過6000)。
然后我會根據創建的五個文本框(tbSearchArticleNo,tbSearchDescription,tbSearchPartNum ...等)發生五個“文本更改”事件。
Private Sub tbSearchArticleNo_TextChanged(sender As Object, e As System.EventArgs) Handles tbSearchArticleNo.TextChanged
If tbSearchDesc.Text <> "" Or tbPartNum.Text <> "" Or tbManufacturer.Text <> "" Or tbCost.Text <> "" Then
SearchCurrentList(lwArticles, tbSearchArticleNo.Text, 0, False)
Else
SearchListView(lwArticles, tbSearchArticleNo.Text, 0, False)
End If
End Sub
這是我的方法SearchCurrentList:
Private Sub SearchCurrentList(ByVal listview As ListView, ByVal search As String, ByVal colIndex As Integer, ByVal upperCase As Boolean)
If upperCase Then
search = search.ToUpper()
End If
listview.BeginUpdate()
'Clear listview
lwArticles.Items.Clear()
'Other textbox has information in it, concatenate both results
For Each item In currentListItems
Dim itemToUpper = item.SubItems.Item(colIndex).Text
If upperCase Then
itemToUpper = item.SubItems.Item(colIndex).Text.ToUpper()
End If
If itemToUpper.Contains(search) Then
lwArticles.Items.Add(item)
End If
Next
'Reupdate the current list of items
currentListItems.Clear()
For Each item In lwArticles.Items
currentListItems.Add(item)
Next
listview.EndUpdate()
End Sub
這是我的方法SearchListView:
Private Sub SearchListView(ByVal listview As ListView, ByVal search As String, ByVal colIndex As Integer, ByVal upperCase As Boolean)
'Upper case parameter determines if you're searching a string, if so, it is better to compare everything by uppercase
If upperCase Then
search = search.ToUpper()
End If
listview.BeginUpdate()
If search.Trim().Length = 0 Then
'Clear listview
listview.Items.Clear()
'Clear currentListItems
currentListItems.Clear()
'If nothing is in the textbox make all items appear
For Each item In originalListItems
listview.Items.Add(item)
Next
Else
'Clear listview
listview.Items.Clear()
'Clear currentListItems
currentListItems.Clear()
'Go through each item in the original list and only add the ones which contain the search text
For Each item In originalListItems
Dim currItem = item.SubItems.Item(colIndex).Text
If upperCase Then
currItem = currItem.ToUpper()
End If
If currItem.Contains(search) Then
currentListItems.Add(item)
listview.Items.Add(item)
End If
Next
End If
listview.EndUpdate()
End Sub
這是我的搜索示例:
tbSearchArticleNo.Text =“33”
這將匹配字符串中包含“33”的每個articleNo。 現在我想添加另一個過濾器:
tbSearchDescription.Text =“混音器”
這應匹配商品編號中包含33的所有內容以及說明中的“調音台”。 依此類推第四名。
實際的過濾器工作正常 - 我唯一的問題是每當我擦除某些東西時,例如“混音器”(雖然文章中仍然有“33”)但它不會返回包含“33”的文章的結果...而是它不會改變我的搜索結果。 可能有更好的搜索方式嗎?
而不是一次只過濾一列並傳遞當前列表以進一步過濾結果,如何讓一個函數一次過濾所有指定的值:
很難按照你想要做的,但我建議如果你在listview中處理6k項目並想要過濾它們,也許你應該使用數據綁定gridview代替。
然后,您可以非常簡單地在數據源上執行搜索:
Public Class Form1
Private _articleList As List(Of Article)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'populate _itemList somehow, for example from a database. Manually here for example purposes:
_articleList = New List(Of Article) From {
New Article("jenny cooks fish", "cooking"),
New Article("a better sales team", "sales")}
DataGridView1.DataSource = _articleList
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim filtered As List(Of Article) = _articleList.Where(Function(x) x.Title.Contains("cook") AndAlso x.Category = "cooking").ToList
DataGridView1.DataSource = filtered
End Sub
End Class
Public Class Article
Property Title As String
Property Category As String
'etc etc
Public Sub New(ByVal title As String, ByVal category As String)
_Title = title
_Category = category
End Sub
End Class
處理此問題的一種不同方式是使用LINQ。 以下函數可用於返回枚舉提供的集合的對象,僅包括適合過濾器的項目。 您可以使用此枚舉器重新填充列表。 如果您每次調用GetFilter時都使用了originalListItems,那么您將始終在最新的過濾器中包含所有項目以供考慮。
Function GetFilter(source As IEnumerable(Of ListViewItem), articleNo As String, description As String,
partNum As String, prop4 As String, prop5 As String) As IQueryable(Of ListViewItem)
GetFilter = source.AsQueryable
Dim articleFilter As Expressions.Expression(Of Func(Of ListViewItem, Boolean)) = _
Function(i As ListViewItem) i.SubItems(0).Text.IndexOf(articleNo, StringComparison.InvariantCultureIgnoreCase) >= 0
Dim descFilter As Expressions.Expression(Of Func(Of ListViewItem, Boolean)) = _
Function(i As ListViewItem) i.SubItems(1).Text.IndexOf(description, StringComparison.InvariantCultureIgnoreCase) >= 0
Dim partFilter As Expressions.Expression(Of Func(Of ListViewItem, Boolean)) = _
Function(i As ListViewItem) i.SubItems(2).Text.IndexOf(partNum, StringComparison.InvariantCultureIgnoreCase) >= 0
Dim prop4Filter As Expressions.Expression(Of Func(Of ListViewItem, Boolean)) = _
Function(i As ListViewItem) i.SubItems(3).Text.IndexOf(prop4, StringComparison.InvariantCultureIgnoreCase) >= 0
Dim prop5Filter As Expressions.Expression(Of Func(Of ListViewItem, Boolean)) = _
Function(i As ListViewItem) i.SubItems(4).Text.IndexOf(prop5, StringComparison.InvariantCultureIgnoreCase) >= 0
If Not String.IsNullOrEmpty(articleNo) Then GetFilter = Queryable.Where(GetFilter, articleFilter)
If Not String.IsNullOrEmpty(description) Then GetFilter = Queryable.Where(GetFilter, descFilter)
If Not String.IsNullOrEmpty(partNum) Then GetFilter = Queryable.Where(GetFilter, partFilter)
If Not String.IsNullOrEmpty(prop4) Then GetFilter = Queryable.Where(GetFilter, prop4Filter)
If Not String.IsNullOrEmpty(prop5) Then GetFilter = Queryable.Where(GetFilter, prop5Filter)
End Function
更好的是,稍微考慮一下,你可以將articleNo和其他參數變成具有更大范圍的變量,並調整函數以將IsNullOrEmpty檢查嵌入到Queryable表達式中,然后你甚至不需要重新生成字段值更改時的過濾器。 您可以將變量設置為新的文本框值並重新評估已生成的過濾器表達式,該表達式將考慮變量中的新值,從而產生新的過濾結果。
以下是我希望它的使用方式:
lwArticles.Items.Clear()
For Each i In GetFilter(originalListItems, tbSearchArticleNo.Text, tbSearchDesc.Text, tbPartNum.Text, tbManufacturer.Text, tbCost.Text)
lwArticles.Items.Add(i)
Next
我設法讓它發揮作用。 對於那些想知道如何,它不是那么優雅 - 但它的工作原理!
我在四個文本框的GUI上設置了標簽(在與工程師進一步交談后,我省略了成本文本框)。 所以..
tbSearchArticleNo.Tag = 1
tbSearchDesc.Tag = 2
tbPartNum.Tag = 4
tbManufacturer.Tag = 8
這並不優雅,因為在添加文本框時,指數會增長。 (注意)根據輸入的字段,計算總數,然后由我的FilterOriginalList(總計)處理
Private Sub tbSearchArticleNo_TextChanged(sender As Object, e As System.EventArgs) Handles tbSearchArticleNo.TextChanged, tbSearchDesc.TextChanged, tbPartNum.TextChanged, tbManufacturer.TextChanged
Dim tag1 As Integer = 0
Dim tag2 As Integer = 0
Dim tag3 As Integer = 0
Dim tag4 As Integer = 0
If tbSearchArticleNo.Text <> "" Then
tag1 = tbSearchArticleNo.Tag
End If
If tbSearchDesc.Text <> "" Then
tag2 = tbSearchDesc.Tag
End If
If tbPartNum.Text <> "" Then
tag3 = tbPartNum.Tag
End If
If tbManufacturer.Text <> "" Then
tag4 = tbManufacturer.Tag
End If
FilterOriginalList(tag1 + tag2 + tag3 + tag4)
End Sub
這是我的方法:
Private Sub FilterOriginalList(ByRef tagCounter As Integer)
Dim field1 As String = tbSearchArticleNo.Text
Dim field2 As String = tbSearchDesc.Text.ToUpper()
Dim field4 As String = tbPartNum.Text.ToUpper()
Dim field8 As String = tbManufacturer.Text.ToUpper()
lwArticles.BeginUpdate()
'Clear listview
lwArticles.Items.Clear()
For Each item In originalListItems
Dim currField1 = item.SubItems.Item(0).Text
Dim currField2 = item.SubItems.Item(1).Text.ToUpper
Dim currField4 = item.SubItems.Item(2).Text.ToUpper
Dim currField8 = item.SubItems.Item(3).Text.ToUpper
Select Case (tagCounter)
Case 0
lwArticles.Items.Add(item)
Case 1
If currField1.Contains(field1) Then
lwArticles.Items.Add(item)
End If
Case 2
If currField2.Contains(field2) Then
lwArticles.Items.Add(item)
End If
Case 3
If currField1.Contains(field1) And currField2.Contains(field2) Then
lwArticles.Items.Add(item)
End If
Case 4
If currField4.Contains(field4) Then
lwArticles.Items.Add(item)
End If
Case 5
If currField1.Contains(field1) And currField4.Contains(field4) Then
lwArticles.Items.Add(item)
End If
Case 6
If currField2.Contains(field2) And currField4.Contains(field4) Then
lwArticles.Items.Add(item)
End If
Case 7
If currField1.Contains(field1) And currField2.Contains(field2) And currField4.Contains(field4) Then
lwArticles.Items.Add(item)
End If
Case 8
If currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 9
If currField1.Contains(field1) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 10
If currField2.Contains(field2) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 11
If currField1.Contains(field1) And currField2.Contains(field2) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 12
If currField4.Contains(field4) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 13
If currField1.Contains(field1) And currField4.Contains(field4) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 14
If currField2.Contains(field2) And currField4.Contains(field4) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
Case 15
If currField1.Contains(field1) And currField2.Contains(field2) And currField4.Contains(field4) And currField8.Contains(field8) Then
lwArticles.Items.Add(item)
End If
End Select
Next
lwArticles.EndUpdate()
End Sub
感謝所有幫助過的人。 這是我找到的解決方案 - 我可能會在未來中尋找更容易的東西!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.