coinbird
coinbird

Reputation: 1217

Filter items in a ListView in real time

My program generates ListView full of information. I type into a text box a name that might match one of the item names in the ListView. I want this typed name to weed out the names from the ListView that don't match.

For example, if I type in "abc", names like "uvw" and "xyz" wouldn't show up anymore, but "abc" and "abcde" would still show up in the list view.

The end goal is to be able to check the checkboxes next to the names I want, and search for more names, eventually selecting several, without resetting the checkboxes.

Right now I click a button and the ListView is populated:

private void button1_Click(object sender, EventArgs e)
{
    List<string> myList = getList();
    foreach(string s in myList)
    {
        listView1.Items.Add(s);
    }
}

getList() just returns a List<string> of all the names I want.

I can't figure out how to make the ListView update in real time when I type in my text box. I'm able to update it with a button click via repopulating the ListView based on looping through the List, and checking each name, but that's not what I want. It also doesn't retain checked check boxes, as it's a newly generated list each time.

I read about a "text change listener", but I'm not sure that's what I should be using here...

Upvotes: 3

Views: 7709

Answers (2)

Handbag Crab
Handbag Crab

Reputation: 1538

With filtering you need some way of remembering which ListViewItems are selected, so instead of inserting all your ListViewItems into your listview you want to instantiate them in a master list. Then attach a TextChanged event handler to your text box and when the text changes you display the items.

List<ListViewItem> masterlist;

public Form1()
{
    InitializeComponent();
    masterlist = new List<ListViewItem>();
}

private void button1_Click(object sender, EventArgs e)
{
    // Populate the masterlist
    masterlist.Clear();
    foreach(string s in getList())
    {
        masterlist.Items.Add(new ListViewItem(s));
    }

    // Display the items in the listview
    DisplayItems();
}

private void DisplayItems()
{
    listView1.Items.Clear();

    // This filters and adds your filtered items to listView1
    foreach(ListViewItem item in masterlist.Where(lvi => lvi.Text.ToLower().Contains(textBox1.Text.ToLower().Trim())))
    {
        listView1.Items.Add(item);
    }
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
    // Re-display the items when the filter changes
    DisplayItems();
}

As you're dealing directly with ListViewItems in your masterlist they will retain their checked state when swapped in and out of listView1.

I have assumed that your filter textbox is called textBox1.

Upvotes: 7

Matt Stannett
Matt Stannett

Reputation: 2728

If you want to go for a full C# solution (rather than using any Javascript), as much as it pains me, I would suggest using an UpdatePanel.

Put your ListBox inside they the <ContentTemplate> section of the <UpdatePanel> then add an <asp:AsyncPostBackTrigger> with the ControlID set to that of your textbox. Make sure that the UpdateMode property of the UpdatePanel is set to "Conditional".

On your TextBox you will also have to set the AutoPostBack property to true. On the TextBox itself you will have to create a TextChanged event handler, then in your code behind (.cs file) you will have the logic for your TextChanged handler which will filter the list then set the new value for your ListBox.

UpdatePanels are ok for simply scenarios, but you can very easily get yourself into trouble by mis-using them.

Upvotes: -1

Related Questions