В приложении C# WPF я использую элемент управления ComboBox со свойством IsEditable="True". Когда я нажимаю клавишу со стрелкой вниз в закрытом поле со списком, следующий элемент в поле со списком выбирается без открытия раскрывающегося списка. Как вместо этого открыть раскрывающийся список при нажатии клавиши со стрелкой вниз, аналогично тому, как я могу открыть его с помощью Alt + Стрелка вниз?
Причина, по которой мне нужна возможность открывать раскрывающийся список с помощью клавиши со стрелкой вниз, заключается в том, что я хочу оптимизировать поведение ComboBox только для клавиатуры и доступности средства чтения с экрана, а моя программа чтения с экрана не предоставляет никакой информации о выбранном в данный момент элементе при изменении выбора элемента в ComboBox. с помощью клавиш со стрелками вниз или вверх, не открывая раскрывающийся список, но предоставляет обратную связь только после навигации по открытому раскрывающемуся списку ComboBox при открытии с помощью Alt + стрелка вниз.
На данный момент у меня есть следующий код, который, к сожалению, не работает, поскольку событие PreviewKeyDown не запускается, если я нажимаю только клавишу со стрелкой вниз без модификатора. Он срабатывает для символов, Alt + стрелка вниз и т. д., но не для стрелки вниз.
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;
}
}
}
🤔 А знаете ли вы, что...
C# является статически типизированным языком, что обеспечивает высокую безопасность и производительность кода.
Мне удалось это сделать на мероприятии PreviewKeyDown
вот так:
private void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
((ComboBox)sender).IsDropDownOpen = true;
}
}
Этот обработчик событий ожидает нажатия клавиши Down
, а затем открывает раскрывающийся список.
Дополню ответ Эфраима Ньюмана. Вы можете изменить поведение элемента, используя «Поведение» или «Прикрепленное свойство». Пример реализации Attached Property:
public class ComboBoxHelper
{
public static bool GetIsDropDownOpenDownArrow(ComboBox cBox)
{
return (bool)cBox.GetValue(IsDropDownOpenDownArrowProperty);
}
public static void SetIsDropDownOpenDownArrow(ComboBox cBox, bool value)
{
cBox.SetValue(IsDropDownOpenDownArrowProperty, value);
}
// Using a DependencyProperty as the backing store for IsDropDownOpenDownArrow. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsDropDownOpenDownArrowProperty =
DependencyProperty.RegisterAttached(
"IsDropDownOpenDownArrow",
typeof(bool),
typeof(ComboBoxHelper),
new PropertyMetadata(false)
{
PropertyChangedCallback = OnIsDropDownOpenDownArrowChanged
});
//private static ConditionalWeakTable<ComboBox, delegate> Handlers;
private static void OnIsDropDownOpenDownArrowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ComboBox cBox = (ComboBox)d;
if (true.Equals(e.NewValue))
{
cBox.AddHandler(UIElement.PreviewKeyDownEvent, DownArrowHandler);
}
else
{
cBox.RemoveHandler(UIElement.PreviewKeyDownEvent, DownArrowHandler);
}
}
private static readonly KeyEventHandler DownArrowHandler = (sender, e) =>
{
if (e.Key == Key.Down)
{
ComboBox cBox = (ComboBox)sender;
if (!cBox.IsDropDownOpen)
{
cBox.IsDropDownOpen = true;
e.Handled = true;
}
}
};
}
Пример использования:
public static class DataExample
{
public static ReadOnlyCollection<int> IntCollection { get; } =
Array.AsReadOnly(Enumerable.Range(0, 10).Select(_ => Random.Shared.Next(100)).ToArray());
}
<UniformGrid Rows = "1">
<ComboBox ItemsSource = "{x:Static local:DataExample.IntCollection}"
SelectedIndex = "0" VerticalAlignment = "Center" HorizontalAlignment = "Center"/>
<ComboBox ItemsSource = "{x:Static local:DataExample.IntCollection}"
SelectedIndex = "0" VerticalAlignment = "Center" HorizontalAlignment = "Center"
local:ComboBoxHelper.IsDropDownOpenDownArrow = "True"/>
</UniformGrid>
Добавьте в проект новый объект класса (SHIFT+F2
), назовите его ComboBoxEx (или как вы предпочитаете), затем замените определение класса этим кодом, сохраняя, конечно, namespace
. Перестройте решение.
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;
}
}
}
Если у вас уже есть поле со списком в XAML, замените имя экземпляра на local:ComboBoxEx
(или любое другое имя, которое вы решили присвоить классу) и запустите проект.
SelectedIndex
сохраняется перед вызовом base.OnPreviewKeyDown(e)
, поскольку поведение по умолчанию перемещает выбор к следующему элементу в списке. Это гарантирует, что при открытии раскрывающегося списка выбранный элемент отображается как текущий текст. Измените по мере необходимости.