Ключ доступа выбирается, даже если мы не нажали клавишу Alt в WPF
У меня есть приложение WPF с панелью инструментов. В панели инструментов у меня есть несколько пользовательских элементов управления в качестве инструментов.
Я установил ключ доступа для каждого элемента управления, он работает нормально.
Проблема заключается в следующем: если я щелкаю пользовательский элемент управления (который состоит из кнопки и метки, я установил ключ доступа для кнопки), заданная задача завершается, но когда я нажимаю любую клавишу доступа, не нажимая клавишу "Alt", она получает выбран.
Есть идеи?
3 ответа
По-видимому, это было преднамеренное изменение со стороны Microsoft. Смотрите ответ Атанаса Коральского здесь:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/14f6f49f-0027-471b-b68c-e7f6ba012012
Мнемоники меню и панели инструментов работают без нажатия клавиши Alt. Мы решили, что у нас будет одинаковое поведение во всех случаях, поэтому доступ к клавише работает без нажатия клавиши Alt.
Я понимаю, что это не соответствует формам, и мы рассмотрим эту проблему и изменим поведение в следующей версии.
Пока в качестве обходного пути вы можете зарегистрировать обработчик класса для всех событий AccessKeyPressed и обработать событие, если клавиша Alt не нажата.
EventManager.RegisterClassHandler(typeof(UIElement), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(OnAccessKeyPressed));
...
private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs e) { if (!e.Handled && e.Scope == null && (e.Target == null || e.Target == label)) { // If Alt key is not pressed - handle the event if ((Keyboard.Modifiers & ModifierKeys.Alt) != ModifierKeys.Alt) { e.Target = null; e.Handled = true; } } }
Также смотрите ответ mfc2wpf:
Я использовал выше, и это работает. Однако это предотвратило действие по умолчанию для Enter и ESC. Поэтому я вставил следующее в верхней части метода.
if (Keyboard.IsKeyDown(Key.Enter) || Keyboard.IsKeyDown(Key.Escape)) return;
Ключи доступа включают в себя Enter и Esc, которые являются ключами по умолчанию для Button
с которых есть IsDefault = true
или же IsCancel = true
, Если вы не хотите требовать Alt+Enter и Alt+Esc для этих кнопок, вам нужно добавить специальное условие в обработчик.
Начиная с.Net 4.5 вы можете настроить это поведение с помощью свойства CoreCompatibilityPreferences.IsAltKeyRequiredInAccessKeyDefaultScope. Чтобы изменить поведение клавиш доступа, чтобы они срабатывали только при нажатии Alt, установите для него значение true.
CoreCompatibilityPreferences.IsAltKeyRequiredInAccessKeyDefaultScope = true;
Как указано в документации, это должно произойти в начале приложения. Установка этого параметра вызовет исключение после того, как он будет прочитан.
Как указано в других ответах, настройка IsAltKeyRequiredInAccessKeyDefaultScope
избегает вызова действий для клавиш доступа без нажатия клавиши Alt. Однако это также может привести к отключению клавиши Enter (для вызова действия по умолчанию) и клавиши Esc (для вызова действия Cancel).
Использование предложенного обходного пути вместо этого и тестирование на Key.Enter
а также Key.Escape
Можете обойти эту проблему. Однако вы можете обнаружить, что пункты меню не могут быть выбраны по их клавише доступа без нажатия клавиши Alt, что может быть проблемой, если кнопка в области видимости использует ту же клавишу доступа.
Тогда альтернативой может быть обработка события ключа доступа путем проверки, может ли AccessText
контроль находится в пределах MenuItem
или нет, что-то вроде этого:
EventManager.RegisterClassHandler(
typeof(UIElement),
AccessKeyManager.AccessKeyPressedEvent,
new AccessKeyPressedEventHandler(OnAccessKeyPressed));
...
static void OnAccessKeyPressed(object accessKeyTarget, AccessKeyPressedEventArgs e)
{
if (!e.Handled && e.Scope == null &&
(Keyboard.Modifiers & ModifierKeys.Alt) != ModifierKeys.Alt &&
!ShouldElementHandleAccessKeysWhenAltIsNotPressed(accessKeyTarget as UIElement))
{
e.Target = null;
e.Handled = true;
}
}
static bool ShouldElementHandleAccessKeysWhenAltIsNotPressed(UIElement element)
{
if (element == null) return false;
var accessText = element as AccessText;
if (accessText != null && !IsDecendantOfMenuItem(accessText)) return false;
return true;
}
static bool IsDecendantOfMenuItem(DependencyObject element)
{
for (; element != null; element = VisualTreeHelper.GetParent(element))
if (element is MenuItem) return true;
return false;
}