Access key getting selected even we did not press 'Alt' key in WPF
Asked Answered
T

3

7

I have WPF application which is having tool bar. In tool bar I have some user controls as tools.

I have set access key to each control, it is working fine.

The issue is: If I click a user control(which is consist of Button and Label, I have set access key for Button) the given task is completed, but when I press any access key without pressing 'Alt' key then it is getting selected.

Any ideas?

Transparent answered 9/12, 2011 at 10:16 Comment(0)
N
4

Apparently, this was a deliberate change by Microsoft. See Atanas Koralski's answer here:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/14f6f49f-0027-471b-b68c-e7f6ba012012

Menu and ToolBar mnemonics work without pressing Alt key. We decided that we will have uniform behavior in all cases so access key work without pressing Alt key.

I understand that this is not in parity with Forms and we will consider this issue and change the behavior in the next version.

For now as a workaround you can register a class handler for all AccessKeyPressed events and handle the event if Alt key is not pressed.

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;
        }
    }
}

Also see mfc2wpf's reply:

I've used the above and it works. However, that prevented the default action for Enter and ESC. So I inserted the following at the top of the method.

if (Keyboard.IsKeyDown(Key.Enter) || Keyboard.IsKeyDown(Key.Escape)) return;

Access keys include Enter and Esc, which are the default keys for Buttons which have IsDefault = true or IsCancel = true. If you don't want to require Alt+Enter and Alt+Esc for those buttons, you would need to add the special condition to the handler.

Newly answered 18/4, 2013 at 12:46 Comment(0)
A
5

As of .Net 4.5 you can configure this behavior with the CoreCompatibilityPreferences.IsAltKeyRequiredInAccessKeyDefaultScope property. To change the access key behavior so that they will only fire when Alt is pressed set it to true.

CoreCompatibilityPreferences.IsAltKeyRequiredInAccessKeyDefaultScope = true;

As the documentation states this must early in the app. Setting it will throw an exception after it has been read.

Alecalecia answered 24/4, 2015 at 21:1 Comment(1)
I have to note that setting IsAltKeyRequiredInAccessKeyDefaultScope to true also disables ENTER and ESC for buttons marked with IsDefault and IsCancel when ALT is not pressed.Iapetus
N
4

Apparently, this was a deliberate change by Microsoft. See Atanas Koralski's answer here:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/14f6f49f-0027-471b-b68c-e7f6ba012012

Menu and ToolBar mnemonics work without pressing Alt key. We decided that we will have uniform behavior in all cases so access key work without pressing Alt key.

I understand that this is not in parity with Forms and we will consider this issue and change the behavior in the next version.

For now as a workaround you can register a class handler for all AccessKeyPressed events and handle the event if Alt key is not pressed.

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;
        }
    }
}

Also see mfc2wpf's reply:

I've used the above and it works. However, that prevented the default action for Enter and ESC. So I inserted the following at the top of the method.

if (Keyboard.IsKeyDown(Key.Enter) || Keyboard.IsKeyDown(Key.Escape)) return;

Access keys include Enter and Esc, which are the default keys for Buttons which have IsDefault = true or IsCancel = true. If you don't want to require Alt+Enter and Alt+Esc for those buttons, you would need to add the special condition to the handler.

Newly answered 18/4, 2013 at 12:46 Comment(0)
T
0

As stated in other answers, setting IsAltKeyRequiredInAccessKeyDefaultScope avoids invoking actions for access keys without pressing the Alt key. However, this can also have the effect of disabling the Enter key (for invoking the default action) and Esc key (for invoking the Cancel action).

Using the suggested workaround instead, and testing for Key.Enter and Key.Escape, can circumvent this problem. However, you might then find that menu items cannot be selected by their access key without pressing the Alt key, which could be a problem if a button in scope uses the same access key.

An alternative could then be to handle the access key event by checking whether a potentially invokable AccessText control is within a MenuItem or not, something along these lines:

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;
}
Threap answered 12/10, 2015 at 14:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.