我的目标是使用多个文本框开发搜索。我有五列(ArticleNo,Description,PartNum,制造商和成本),每列都有一个文本框。
我使用以下方式跟踪原始列表项:
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”的每篇文章。现在我想添加另一个过滤器:
tbSearchDescription.Text =“混音器”
这应匹配商品编号中包含33的所有内容以及说明中的“调音台”。等等等等。第四。
实际过滤器工作正常 - 我唯一的问题是每当我擦除某些内容时,例如“Mixer”(在文章中仍然有“33”)它不会返回包含“33”的articleNo的结果。 ..相反,它不会改变我的搜索结果。可能有更好的搜索方式吗?
答案 0 :(得分:1)
不是一次只过滤一列并传递当前列表以进一步过滤结果,而是让一个函数同时根据所有指定值进行过滤:
答案 1 :(得分:1)
很难理解你想要做的事情,但我建议如果你在列表视图中处理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
答案 2 :(得分:1)
处理此问题的一种不同方式是使用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
答案 3 :(得分:0)
我设法让它发挥作用。对于那些想知道怎么样的人来说,它并不那么优雅 - 但它确实有效!
我在四个文本框的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
感谢所有帮助过的人。这是我找到的解决方案 - 我可能会在未来中看到更容易的东西!