如何在C#中使用文本框搜索ListView的项目

3

我有一个名为listView1的列表视图,其中包含计算机ID和它们的一些信息。所以我想做的是,我有一个名为filterbox的文本框,当我输入内容时,它将进行过滤,这很好用。我的问题是它只查找第一列而不是其他列。例如:

PCNAME  USER  MODEL
 AAAA   JOHN  DELL
 BBBB   MIKE  TOSHIBA
 CCCC   ASH   MONSTER

当我输入BB时,它只获取第二行并且运行良好,但如果我输入DELL,则什么也没有。
  private void filterbox_TextChanged(object sender, EventArgs e)
        {
            if (filterbox.Text != "")
            {
                for (int i = listView1.Items.Count - 1; i >= 0; i--)
                {
                    var item = listView1.Items[i];
                    if (item.Text.ToLower().Contains(filterbox.Text.ToLower()))
                    {
                        item.BackColor = SystemColors.Highlight;
                        item.ForeColor = SystemColors.HighlightText;
                    }
                    else
                    {
                        listView1.Items.Remove(item);
                    }
                }
                if (listView1.SelectedItems.Count == 1)
                {
                    listView1.Focus();
                }
            }
        }

2
你想搜索项目的子项目吗?那就开始吧!从SubItems[1]开始,因为[0]是项目本身! - undefined
不需要使用for (int i ..,你可以直接使用listView1.Items.Where进行筛选。而且不需要移除项目,只需清空/刷新ListView即可。 - undefined
2
链接中的答案似乎没有考虑子项。 - undefined
Items.Where(i=> i.Any(sub=> sub.SubItems ) - undefined
@Saruman,所以OfType<ListViewItem>()。我的手头上没有IDE,但是应该像这样 ListView.remove(datasource.Where()) - undefined
显示剩余2条评论
3个回答

4
这很简单,只需迭代子项即可:
foreach (ListViewItem item in listView1.Items)
   foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
      if (subitem.Text.Equals(filterbox.Text, StringComparison.OrdinalIgnoreCase))
      {
         item.BackColor = SystemColors.Highlight;
         item.ForeColor = SystemColors.HighlightText;
         break;
      }

注意,您在这里还有其他事情要处理,但是我将把它们的细节留给您。

更新

为了过滤,你可以使用一些Linq:

if (filterbox.Text == "")
{
   return;
}

var list = listView1.Items
                    .Cast<ListViewItem>()
                    .Where(
                        x => x.SubItems
                              .Cast<ListViewItem.ListViewSubItem>()
                              .Any(y => y.Text.Contains(filterbox.Text)))
                    .ToArray();
listView1.Items.Clear();
listView1.Items.AddRange(list);

1
与原帖中的代码不同,应该调用text.Contains(searchText)而非Equals方法。 - undefined
2
它给出了很多错误 - 胡说八道。它只给出一个错误;将, StringComparison.OrdinalIgnoreCase删除并将该行更改为.Any(y => y.Text.Contains(filterbox.Text))),代码就可以正常工作了。 - undefined
1
@TaW 你说得对,它确实起作用了,它在每一列进行过滤,但还有一个问题,当我删除字符时,它什么都不给我? - undefined
1
从@TaW的代码中过滤它,但再次更改文本将会得到一个空白页面。 - undefined
1
确实,答案还不完整。以下是纠正的步骤:创建一个类级变量来保存所有项目:List<ListViewItem> allItems = new List<ListViewItem>();。在添加项目时填充它:allItems.AddRange(listView1.Items.Cast<ListViewItem>());。并在过滤时使用它:var list = allItems.Cast<ListViewItem>().. - undefined
显示剩余8条评论

4

Saruman的回答核心非常好:使用linq将符合条件的所有项复制到可枚举集合中,清除listview项目并AddRange好的项。

然而,为了得到完全有效的解决方案,需要进行一些更正。

首先:我们需要在类级别变量中存储完整的项目集:

List<ListViewItem> allItems = new List<ListViewItem>();

我们需要在完整的项目集添加后再填写它:
allItems.Clear();
allItems.AddRange(listView1.Items.Cast<ListViewItem>());

现在我们可以编写 filterTextbox 的 TextChanged 事件代码; 在这里,我们始终使用完整的数据集:
private void filterbox_TextChanged(object sender, EventArgs e)
{
    listView1.Items.Clear();   // clear all items we have atm
    if (filterbox.Text == "")
    {
        listView1.Items.AddRange(allItems.ToArray());  // no filter: add all items
        return;
    }
    // now we find all items that have a suitable text in any subitem/field/column
    var list = allItems.Cast<ListViewItem>()
                       .Where( x => x.SubItems
                                     .Cast<ListViewItem.ListViewSubItem>()
                                     .Any(y => y.Text.Contains(filterbox.Text)))
                       .ToArray();
    listView1.Items.AddRange(list);  // now we add the result
}

向编写带有必要Casts的linq的Saruman致敬!

顺便说一下:我们应该并且确实使用Cast而不是OfType,因为我们可以确定类型。 Cast速度稍快。


2
你可以将列表视图与数据表绑定。参见将列表视图与数据表绑定。在文本框“文本更改/控件离开”事件中,在数据表上应用过滤器。这将负责更新列表视图的项目,因为它的数据源已绑定到数据表。
listView1.ItemsSource = dataTable.DefaultView;

使用以下查询来过滤数据。
DataView dv = new DataView(yourDatatable);
dv.RowFilter = "query"; // query example = "id = 10"

让我知道是否有帮助。:)


RowFilter很好,但是ListView(包含不规则数组)在与表格进行数据绑定时非常糟糕。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接