简体   繁体   中英

How can I implement incremental search on a listbox?

I want to implement incremental search on a list of key-value pairs, bound to a Listbox.

If I had three values (AAB, AAC, AAD), then a user should be able to select an item in the available list box and type AAC and this item should be highlighted and in focus. It should be also in incremental fashion.

What is the best approach to handle this?

Add a handler to the KeyChar event (the listbox is named lbxFieldNames in my case):

private void lbxFieldNames_KeyPress(object sender, KeyPressEventArgs e)
{
  IncrementalSearch(e.KeyChar);
  e.Handled = true;
}

(Important: you need e.Handled = true; because the listbox implements a "go to the first item starting with this char" search by default; it took me a while to figure out why my code was not working.)

The IncrementalSearch method is:

private void IncrementalSearch(char ch)
{
  if (DateTime.Now - lastKeyPressTime > new TimeSpan(0, 0, 1))
    searchString = ch.ToString();
  else
    searchString += ch;
  lastKeyPressTime = DateTime.Now;

  var item = lbxFieldNames
    .Items
    .Cast<string>()
    .Where(it => it.StartsWith(searchString, true, CultureInfo.InvariantCulture))
    .FirstOrDefault();
  if (item == null)
    return;

  var index = lbxFieldNames.Items.IndexOf(item);
  if (index < 0)
    return;

  lbxFieldNames.SelectedIndex = index;
}

The timeout I implemented is one second, but you can change it by modifying the TimeSpan in the if statement.

Finally, you will need to declare

private string searchString;
private DateTime lastKeyPressTime;

If I'm interpreting your question correctly, it seems like you want users to be able to start typing and have suggestions made.

You could use a ComboBox (instead of a ListBox):

  1. Set the DataSource to your list of KeyValuePairs,
  2. Set the ValueMember to "Key" and the DisplayMember to "Value",
  3. Set AutoCompleteMode to SuggestAppend, and
  4. Set AutoCompleteSource to ListItems

You can use the TextChanged event to fire whenever the user enter a char, and you can also use the listbox event DataSourceChanged with it to hover a specific item or whatever you want.

I will give you an example:

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        listBox1.DataSource = GetProducts(textBox1.Text);
        listBox1.ValueMember = "Id";
        listBox1.DisplayMember = "Name";
    }

    List<Product> GetProducts(string keyword)
    {
        IQueryable q = from p in db.GetTable<Product>()
                       where p.Name.Contains(keyword)
                       select p;
        List<Product> products = q.ToList<Product>();
        return products;
    }

So whenever the user start to enter any char the getproducts method executes and fills the list box and by default hover the first item in the list you can handle that also using the listbox event DataSourceChanged to do whatever you want to do.

There is also another interesting way to do that, which is: TextBox.AutoCompleteCustomSource Property :

textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
AutoCompleteStringCollection stringCollection = 
    new AutoCompleteStringCollection();
textBox1.AutoCompleteCustomSource = stringCollection;

This list can take only string[] , so you can get them from your data source then when the text changed of the textbox add the similar words from your data source which had been filled into the textbox autocomplete custom source:

private void textBox1_TextChanged(object sender, EventArgs e)
    {
        listBox1.Items.Clear();
        if (textBox1.Text.Length == 0)
        {
            listbox1.Visible = false;
            return;
        }

        foreach (String keyword in textBox1.AutoCompleteCustomSource)
        {
            if (keyword.Contains(textBox1.Text))
            {
                listBox1.Items.Add(keyword);
                listBox1.Visible = true;
            }
        }

    }

Add another event ListBoxSelectedindexchanged to add the selected text to the text box

Maybe you could add an event for TextChanged on the control where the user is typing is search (i'm guessing a TextBox ). In the event, you could loop through all items to search the one that is the most corresponding to the words typed by the user.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM