0

How to select item by typing a keyboard letter key in WPF combobox?

I would like to be able to select the first item on the items first letter matching the key pressed in a listbox, A-Z when the listbox is in focus.

<ListBox x:Name="List" ItemContainerStyle="{StaticResource ListBoxItem}" DataContext="{StaticResource VM}" 
                        ItemsSource="{Binding Names, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" DisplayMemberPath="Name"
                             Style="{StaticResource ResourceKey=ListBox}"/>
Going-gone
  • 282
  • 1
  • 14
  • 1
    if you can tell us what have you tried so far in uwp and show us the code so we can know how are you binding data to your combobox, it will be more easy to give you a solution. – Muhammad Touseef Sep 24 '18 at 21:56
  • I edited to show, I know that the link does this with a combobox, but I'm needing this done with a listbox. – Going-gone Sep 25 '18 at 12:18

2 Answers2

1

When you are binding the ItemSource of your combobox to an collection within your ViewModel then all you need to do is catch the KeyDown event on your ComboBox and then filter the items accordingly, then select the item you want. and lastly just use the StartBringIntoView() method to scroll that item in front of the user.

private void MyComboBox_KeyDown(object sender, KeyRoutedEventArgs args)
{
    if (e.Key == Windows.System.VirtualKey.E)
    {
        //Now you need to select the first item which starts with letter E.
        //Assuming your combobox's itemssource has a binding to a collection named "MyCollection" then this is how you can achieve it :
        var item = MyCollection.First(a=>a.StartsWith("E"));
        //Now you can set this item to the SelectedItem property of your combobox or you can get its index in the collection and then set SelectedIndex of your combobox.
        var index = MyCollection.IndexOf(item);
        MyComboBox.SelectedIndex = index;//now you have selected the desired item
        //LastStep is to bring that selected item into view of the user.
        MyComboBox.SelectedItem.StartBringIntoView();
    }
}

Note that StartBringIntoView is only available in Windows 10 SDK creators update and above.

Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75
  • Can this be done with a listbox, and also would you be able to show me in MVVM form? – Going-gone Sep 25 '18 at 12:19
  • 1
    yes it can be done exactly the same way in listbox as well and if you are using mvvm you can just access your colletion like vm.MyCollection and all other logic will remain the same. – Muhammad Touseef Sep 25 '18 at 14:00
  • It doesn't see any of the data when i do _var item vm.collection.First(a=>a.StartsWith("E"));_ the collection is null. – Going-gone Sep 25 '18 at 15:32
  • 1
    well then that is a different error, you are not initializing your collection then how are you even binding it to the UI, that is why I said we need to see the view model and also your code behind so we can see how exactly are you populating your listbox. – Muhammad Touseef Sep 25 '18 at 15:36
  • Yep, you are correct on not initializing the collection, that was my bad. I marked yours as the answer. Thank you! – Going-gone Sep 25 '18 at 15:53
  • I am curious though, How do you focus the listbox without initially selecting a item, and still have the ability to select a item per key clicked? – Going-gone Sep 25 '18 at 16:02
  • 1
    you can programatically set the focus on any control with 'mycontrol.Focus()' – Muhammad Touseef Sep 25 '18 at 17:30
1

This method worked well for me. It's a bit more complex than touseefbsb's answer but I think they both will work.

private async void StatesList_KeyUp(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
    {
        if (!(e.Key >= Windows.System.VirtualKey.A && e.Key <= Windows.System.VirtualKey.Z))
            return;
        string searchLetter = e.Key.ToString();
        ObservableCollection<Type> Names = (ObservableCollection<Type>)List.ItemsSource;
        Type thingToFind;
        if (List.SelectedItem == null)
        {
            thingToFind = Names.Where(x => x.Name.StartsWith(searchLetter)).FirstOrDefault();
        }
        else
        {
            string CurrentName = ((Type)List.SelectedItem).Name;
            var laterItems = Names.Where(x => x.Name.CompareTo(CurrentName) > 0).ToList();
            thingToFind = laterItems.Where(x => x.Name.StartsWith(searchLetter)).FirstOrDefault();
        }
        List.SelectedItem = thingToFind;
        if (thingToFind == null)
            return;
        List.ScrollIntoView(thingToFind);
   }
Going-gone
  • 282
  • 1
  • 14