Reputation: 83
Could anyone please tell me what i should do programmatically to be able to select an item in a listbox using the keyboard when there are multiple items starting with the same character/s. For eg,
If i want to get the focus on "Once" by typing o,n,c what should i do? Instead of jumping from one item to the other as opposed to the default behaviour.
Upvotes: 3
Views: 5581
Reputation: 11
I just modified Abbas code for my case. This is my desktop program and using in one of the form which has ListBox control. This is working great for me. Thanks to Abbas
private DateTime _lastKeyPress;
private string _searchString;
private void lstEmployer_KeyPress(object sender, KeyPressEventArgs e)
{
var newDate = DateTime.Now;
var diff = newDate - _lastKeyPress;
if (diff.TotalSeconds >= 2)
_searchString = string.Empty;
_searchString += e.KeyChar;
lstEmployer.SelectedIndex = lstEmployer.FindString(_searchString);
_lastKeyPress = newDate;
e.Handled = true; //REALLY IMPORTANT TO HAVE THIS
}
Upvotes: 0
Reputation: 86779
You want to use the LBS_SORT
list box style. This style cannot be applied after the control has been created and so to add this style you need to override the CreateParams
property. Create a class (lets call it SortedListBox
) which derives from ListBox
and override this property like so
public class MyListBox : ListBox
{
protected override CreateParams CreateParams
{
get
{
var returnValue = base.CreateParams;
returnValue.Style |= 0x2; // Add LBS_SORT
returnValue.Style ^= 128; // Remove LBS_USETABSTOPS (optional)
return returnValue;
}
}
}
This list box should now both sort the items in your list & support incremental searching (you can't turn the sorting off I'm afraid, if you need to control the sort order then you need to do the incremental searching yourself, as Abbas has suggested)
Update: If you additionally remove the LBS_USETABSTOPS
style you even get an edit carret showing what character the incremental search is currently matching on
Upvotes: 3
Reputation: 14432
Add a KeyPress event handler to the ListBox and track the keys that are pressed. Then compare the complete value that already has been typed to the values from the items in the ListBox. If there's a match, select the item.
Edit:
Here's a solution that I created that works. I also measure the time between keypresses. This way, if the time between to keypresses is more than 1.5 seconds, the search-string is emptied and re-filled with the last search-character. After that it's like I said: find a match and if there's a match, select that item. The two private fields are class-level fields to keep track of the time of the last keypress and the string is to store the search-string.
private DateTime _lastKeyPress;
private string _searchString;
private void ListBox1KeyPress(object sender, KeyPressEventArgs e)
{
var newDate = DateTime.Now;
var diff = newDate - _lastKeyPress;
if (diff.TotalSeconds >= 1.5)
_searchString = string.Empty;
_searchString += e.KeyChar;
for (var i = 0; i < listBox1.Items.Count; i++)
{
var item = listBox1.Items[i].ToString();
if (item.ToLower().StartsWith(_searchString))
{
listBox1.SelectedItem = item;
break;
}
}
_lastKeyPress = newDate;
e.Handled = true; //REALLY IMPORTANT TO HAVE THIS
}
And here's an example using LinQ to get a match for the searchitem:
private void ListBox1KeyPress(object sender, KeyPressEventArgs e)
{
var newDate = DateTime.Now;
var diff = newDate - _lastKeyPress;
if (diff.TotalSeconds >= 1.5)
_searchString = string.Empty;
_searchString += e.KeyChar;
var found = listBox1.Items.Cast<object>().Select(t => t.ToString()).Where(item => item.ToLower().StartsWith(_searchString)).FirstOrDefault();
if(!String.IsNullOrEmpty(found))
listBox1.SelectedItem = found;
_lastKeyPress = newDate;
e.Handled = true;
}
Hope this helps! ;)
Edit2:
I don't know if you noticed the comment with the imortance of the e.Handled
. By default if you press a key in the ListBox, the control will select the first-found item with that key-character. But it has not the functionality that my code has. So, if you remote the e.Handled
line, the code will work but the control will also process the keypress and you don't want that: items will not be correctly selected!
Upvotes: 4