ARr0w ARr0w - 3 months ago 27
C# Question

How to execute advance Listview Search

Using Windows forms, My 'listview' have multiple columns as shown in the picture.

enter image description here

I have been trying to make this txtbox_search to be advanced. When any character, word or number is inserted, i want Some columns of my listview to be traversed to look for the character, word, number and bring up data related to the input.




Like when i enter: txtbox_search.Text = "a"

It should travers column "Name" and fill Listview with data:

entire row that has a name which starts with "a" such as "Anwar"

entire row that has a name which starts with "a" such as "Anas"

so on with entire rows that has a name which starts with "A..."




when i enter: txtbox_search.Text = "1"

It should travers column "ID" and fill Listview with data:

entire row that has a ID which starts with "1" such as "1002"

entire row that has a ID which starts with "1" such as "1112"

so on with entire rows that has a ID which starts with "1..."




so far i have been trying this for 2 days and end up with this much:

private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.Text == textBox_DEC_Search.Text)
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.Add(Items);
}
}
if(textBox_DEC_Search.Text == "" || textBox_DEC_Search.Text == string.Empty)
{
CusList Cus = new CusList();
Cus.CustomersList(listView_DEC_CustomerList);
}
}


This code only travers first column and bring up data that matches the inserted ID, only if the Complete ID matches with txtbox_search.Text how can i make this possible? (i want it to be on client side, not from sql/database). Guides and sample code helps will be really appreciated. Thanks.

Answer

To distinguish between your 2 criteria you could use the following:

if (textBox_DEC_Search.Text.All(x => Char.IsNumber(x)))
{
    Debug.WriteLine("Number");
    // search through ID
}
else
{
    Debug.WriteLine("Name");
    // search through Name
}

It basically checks whether your input is solely numeric.

EDIT:

To check for similarity you cold use String.StartsWith of String.Contains to make the search a little more flexible

to look for the ID or NAME you need to access the subitems!

since ID is your first column check SubItems[0]

if(Items.SubItems[0].Text.StartsWith(textBox_DEC_Search.Text) || 
   Items.SubItems[0]Text.Contains(textBox_DEC_Search.Text))

since NAME is your second column check SubItems[1]

if(Items.SubItems[1].Text.StartsWith(textBox_DEC_Search.Text) || 
   Items.SubItems[1]Text.Contains(textBox_DEC_Search.Text))

One Problem is this line:

listView_DEC_CustomerList.Items.Clear();

because it will erase the first found result when the second is found. So if you find 10 matches the previous 9 will be deleted! I suggest to make first the entire search and then add the results if there are any:

private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
    // index is 0 if numeric for ID or 1 if not for NAME
    int ind = textBox_DEC_Search.Text.All(x => Char.IsNumber(x)) ? 0 : 1;


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

    foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
    {
        if(Items.SubItems[ind].Text.StartsWith(textBox_DEC_Search.Text) || 
          Items.SubItems[ind]Text.Contains(textBox_DEC_Search.Text))            
        {
            matchlist.Add(Items);
        }
    }

    // if you have found something add the all results
    if(matchlist.Any())            
    {
        listView_DEC_CustomerList.Items.Clear();
        listView_DEC_CustomerList.Items.AddRange(matchlist.ToArray());
    }
}

Disclaimer: Although this solution should work I would vote to follow the advice of @RezaAghaei. It is less messy and confusing than directly manipulating the ListView