Reputation: 254
I have a listview name listView1 and it contains computer id's and their some infos.So what I want to do is I have a textbox name filterbox and when I write something it will filter it,it works fine.My problem is it just look for the first column not the others.For example ;
PCNAME USER MODEL
AAAA JOHN DELL
BBBB MIKE TOSHIBA
CCCC ASH MONSTER
when I type BB it just gets the second row and it works fine but if I type DELL it gets me nothing.
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();
}
}
}
Upvotes: 3
Views: 4947
Reputation: 81493
It's as simple as iterating the sub items:
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;
}
Note, you had other things going on here, however I'll leave them details up to you.
For filtering you could use some 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);
Upvotes: 4
Reputation: 54433
The core of Saruman's answer works pretty well: Copy all items that fit the criteria into an enumerable collection with linq, clear the listview items and AddRange
the good ones.
A few corrections are needed however for a fully working solution.
First: We need store the full set of items somewhere. Best in a class level variable:
List<ListViewItem> allItems = new List<ListViewItem>();
We need to fill it after the full set of items has been added:
allItems.Clear();
allItems.AddRange(listView1.Items.Cast<ListViewItem>());
Now we can code the TextChanged
event of our filterTextbox; here we always use the full set of data:
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
}
Kudos to Saruman who wrote the linq with the necessary Casts
!
Btw: We should and do use Cast
instead of OfType
because we can be sure of the types. Cast
is a bit faster.
Upvotes: 4
Reputation: 89
You can bind your list-view with data table. refer bind list-view with data-table . And on text-box "text changed/control leave" event apply filter on data-table. This will take care of updating items of the list-view as it's data source is bound to data-table.
listView1.ItemsSource = dataTable.DefaultView;
Filter data using below query.
DataView dv = new DataView(yourDatatable);
dv.RowFilter = "query"; // query example = "id = 10"
Let me know if it helps. :)
Upvotes: 2