Reputation: 4069
I have a ListView control which contains 4 columns. Filename, ID, Type, Items. I add items to the ListView by reading in a pipe delimited file which contains the necessary fields. All works great and the ListView displays my data. However I'd like to add a search feature so the user can search through the ListView and filter it's Items to only those which match the search text. I would prefer to be able to have the list filtered as they type, if possible. My listview is using the Details view, with columns defined matching the above 4 columns.
I've tried the following code so far, but just can not figure out how to make it work. My restoreAllItems method works fine, and restores the listview to contain all items as if the search textbox was empty.
THIS IS A WIN FORMS APPLICATION
Can someone please help point me in the right direction?
Thank you in advance!!!
private void txtJobSearch_TextChanged(object sender, EventArgs e)
{
// Search items in our Jobs ListView, remove those that do not match search
if (txtJobSearch.Text != String.Empty)
{
for (int i = listJobs.Items.Count - 1; i >= 0; i--)
{
if (listJobs.Items[i].Text.ToLower().Contains(txtJobSearch.Text.ToLower()))
{
listJobs.Items[i].BackColor = SystemColors.Highlight;
listJobs.Items[i].ForeColor = SystemColors.HighlightText;
}
else
{
for (int x = listJobs.Items[i].SubItems.Count - 1; x >= listJobs.Items[i].SubItems.Count; x--)
{
if (listJobs.Items[i].SubItems[x].Text.ToLower().Contains(txtJobSearch.Text.ToLower()))
{
listJobs.Items[i].BackColor = SystemColors.Highlight;
listJobs.Items[i].ForeColor = SystemColors.HighlightText;
}
else
{
listJobs.Items[i].Remove();
}
}
}
}
}
else
{
restoreAllItems("jobs");
}
}
Upvotes: 2
Views: 4312
Reputation:
You don't have to do all of that anymore. It has a function built in. It searches all columns.
ListViewItem foundItem = listJobs.FindItemWithText(txtJobSearch.Text.ToLower());
if (foundItem != null)
{
foundItem.BackColor = Color.Yellow;
foundItem.Selected = true;
}
Upvotes: 2
Reputation: 71
I changed up the function to return an index to the found item but also to select and position into view. This is code being used for a chemical detection and emergency response lookup that's why the listview is named listViewChemical.
private int ItemMatches(string text)
{
bool matches = false;
int idx = -1;
for (int i = chemicalSearchIndex; i < listViewChemical.Items.Count; i++)
{
ListViewItem item = listViewChemical.Items[i];
matches |= item.Text.ToLower().Contains(text.ToLower());
if (matches)
{
idx = item.Index;
break;
}
if (!checkBoxFormulaOnly.Checked)
{
foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
{
matches |= subitem.Text.ToLower().Contains(text.ToLower());
if (matches)
{
idx = item.Index;
break;
}
}
}
}
if (idx >= 0)
{
listViewChemical.Items[idx].EnsureVisible();
listViewChemical.Items[idx].Selected = true;
listViewChemical.Select();
chemicalSearchIndex = idx + 1;
if (chemicalSearchIndex >= listViewChemical.Items.Count)
{
chemicalSearchIndex = 0; //go back to top
}
}
else
{
//No matches
chemicalSearchIndex = 0; //set next find or next to start at the beginning of the list
}
return idx;
}
Upvotes: 1
Reputation: 1735
I've updated your code a bit. Highlighting logic is removed since I don't fully understand it's purpose, but you can easily put it back in place.
The following code operates on the same form as yours. The only exception is ReinitList()
method that is implemented for testing purposes.
// check if current item matches search string
private bool ItemMatches(ListViewItem item, string text)
{
bool matches = false;
matches |= item.Text.ToLower().Contains(text.ToLower());
if (matches)
{
return true;
}
foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
{
matches |= subitem.Text.ToLower().Contains(text.ToLower());
if (matches)
{
return true;
}
}
return false;
}
private void txtJobSearch_TextChanged(object sender, EventArgs e)
{
// prevent flickering
listJobs.BeginUpdate();
// restore all items in case user deletes some characters in the textbox
ReinitList();
string search = txtJobSearch.Text;
// Search items in our Jobs ListView, remove those that do not match search
if (search != String.Empty)
{
for (int i = listJobs.Items.Count - 1; i >= 0; i--)
{
ListViewItem currentItem = listJobs.Items[i];
if (ItemMatches(currentItem, search))
{
// highlight, or move highlighting to ItemMatches
}
else
{
listJobs.Items.RemoveAt(i);
}
}
}
listJobs.EndUpdate();
}
private void ReinitList()
{
listJobs.Items.Clear();
for (int i = 0; i < 50; i++)
{
ListViewItem item = new ListViewItem(i.ToString());
item.SubItems.Add("sub " + i.ToString());
item.SubItems.Add("sub a" + i.ToString());
item.SubItems.Add("sub b" + i.ToString());
listJobs.Items.Add(item);
}
}
private void Form1_Load(object sender, EventArgs e)
{
ReinitList();
}
Upvotes: 3