Search code examples
c#.netwpfwindowsaccessibility

How to open ComboBox dropdown with Down arrow key


In C# WPF application, I am using a ComboBox control with the IsEditable="True" property. When I press the Down arrow key on closed ComboBox, the next item in the ComboBox is selected without opening the dropdown. How to instead open the dropdown when the down arrow key is pressed, similar to how I can open it with Alt + Down arrow?

The reason I need the possibility to open dropdown using Down arrow key is that I want to optimize the ComboBox behavior for keyboard only and screen reader accessibility, and my screen reader does not provide any feedback about the currently selected item when changing item selection in ComboBox using the Down or Up arrow keys without opening the dropdown, but does provide feedback only after navigating within opened ComboBox dropdown when opened via Alt + Down arrow.

So far, I have the following code, which unfortunately does not work as the PreviewKeyDown event does not get fired if I press only the Down Arrow key without modifier. It gets fired for characters, Alt + down arrow etc. but not for down arrow.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        commandComboBox.PreviewKeyDown += new KeyEventHandler(commandComboBox_PreviewKeyDown);
    }

    private void commandComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Down && !commandComboBox.IsDropDownOpen)
        {
            commandComboBox.IsDropDownOpen = true;
        }
    }

    }

Solution

  • Add a new class object to the Project (SHIFT+F2), name it ComboBoxEx (or whatever you prefer), then replace the class definition with this code, preserving the namespace, of course. Rebuild the Solution.

    using System.ComponentModel;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    [ToolboxItem(true)]
    public class ComboBoxEx : ComboBox
    {
        public ComboBoxEx() { }
    
        protected override void OnPreviewKeyDown(KeyEventArgs e) {
            int index = SelectedIndex;
            base.OnPreviewKeyDown(e);
            if (e.Key == Key.Down && !IsDropDownOpen) {
                IsDropDownOpen = true;
                SelectedIndex = index;
            }
        }
    }
    

    If you already have a ComboBox in the XAML, replace the instance name with local:ComboBoxEx (or whatever name you decided to assign to the class) and run the Project.

    The SelectedIndex is stored before calling base.OnPreviewKeyDown(e), because the default behavior moves the selection to the next item in the list. This ensures that, when the drop-down is opened, the item selected is the one shown as the current text. Modify as required.