Ключ доступа выбирается, даже если мы не нажали клавишу 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;
}
Другие вопросы по тегам