Menu Access Keys in WPF Menu Access Keys in WPF wpf wpf

Menu Access Keys in WPF


See my blog post:http://coderelief.net/2012/07/29/wpf-access-keys-scoping/

Let me know if this works for you, it has corrected the issue for me.

using System.Windows.Media;namespace System.Windows.Input{    /// <summary>    /// Contains attached dependency properties to correct the scoping of access keys    /// within the WPF framework.    /// </summary>    public static class AccessKeysManagerScoping    {        /// <summary>        /// Attached dependency property to enable or disable scoping of access keys.        /// </summary>        public static readonly DependencyProperty IsEnabledProperty            = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),            typeof(AccessKeysManagerScoping), new PropertyMetadata(false, OnIsEnabledChanged));        /// <summary>        /// Gets the value of the <see cref="F:IsEnabledProperty"/> attached        /// dependency property for a given dependency object.        /// </summary>        /// <param name="d">The dependency object.</param>        /// <returns>Returns the attached dependency property value.</returns>        [AttachedPropertyBrowsableForType(typeof(DependencyObject))]        public static bool GetIsEnabled(DependencyObject d)        {            return (bool)d.GetValue(IsEnabledProperty);        }        /// <summary>        /// Sets the value of the <see cref="F:IsEnabledProperty"/> attached        /// dependency property for a given dependency object.        /// </summary>        /// <param name="d">The dependency object.</param>        /// <param name="value">The value.</param>        public static void SetIsEnabled(DependencyObject d, bool value)        {            d.SetValue(IsEnabledProperty, value);        }        private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            if (d == null)                return;            if ((bool)e.NewValue)                AccessKeyManager.AddAccessKeyPressedHandler(d, new AccessKeyPressedEventHandler(HandleAccessKeyPressed));            else                AccessKeyManager.RemoveAccessKeyPressedHandler(d, new AccessKeyPressedEventHandler(HandleAccessKeyPressed));        }        /// <summary>        /// Fixes access key scoping bug within the WPF framework.        /// </summary>        /// <param name="sender">Potential target of the current access keys.</param>        /// <param name="e">        /// Info object for the current access keys and proxy to effect it's confirmation.        /// </param>        /// <remarks>        /// The problem is that all access key presses are scoped to the active window,        /// regardless of what properties, handlers, scope etc. you may have set. Targets        /// are objects that have potential to be the target of the access keys in effect.        ///         /// If you happen to have a current object focused and you press the access keys        /// of one of it's child's targets it will execute the child target. But, if you        /// also have a ancestor target, the ancestor target will be executed instead.        /// That goes against intuition and standard Windows behavior.        /// The root of this logic (bug) is within the HwndSource.OnMnemonicCore method.        /// If the scope is set to anything but the active window's HwndSource, the        /// target will not be executed and the handler for the next target in the chain        /// will be called.        /// This handler gets called for every target within the scope, which because        /// of the bug is always at the window level of the active window. If you set        /// e.Handled to true, no further handlers in the chain will be executed. However        /// because setting the scope to anything other than active window's HwndSource        /// causes the target not to be acted on, we can use it to not act on the target        /// while not canceling the chain either, thereby allowing us to skip to the next        /// target's handler. Note that if a handler does act on the target it will        /// inheritably break the chain because the menu will lose focus and the next        /// handlers won't apply anymore; because a target has already been confirmed.        /// We will use this knowledge to resolve the issue.        /// We will set the scope to something other than the active window's HwndSource,        /// if we find that the incorrect element is being targeted for the access keys        /// (because the target is out of scope). This will cause the target to be        /// skipped and the next target's handler will be called.        /// If we detect the target is correct, we'll just leave everything alone so the        /// target will be confirmed.        ///         /// NOTE: Do not call AccessKeyManager.IsKeyRegistered as it will cause a        /// <see cref="T:System.StackOverflowException"/> to be thrown. The key is        /// registered otherwise this handler wouldn't be called for it, therefore        /// there is no need to call it.        /// </remarks>        private static void HandleAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)        {            FrameworkElement focusedElement = Keyboard.FocusedElement as FrameworkElement;            if (focusedElement == null)                return; // No focused element.            if (sender == focusedElement)                return; // This is the correct target.            // Look through descendants tree to see if this target is a descendant of            // the focused element. We will stop looking at either the end of the tree            // or if a object with multiple children is encountered that this target            // isn't a descendant of.            // If no valid target is found, we'll set the scope to the sender which            // results in skipping to the next target handler in the chain            // (due to the bug).            DependencyObject obj = focusedElement as DependencyObject;            while (obj != null)            {                int childCount = VisualTreeHelper.GetChildrenCount(obj);                for (int i = 0; i < childCount; i++)                {                    if (VisualTreeHelper.GetChild(obj, i) == sender)                        return; // Found correct target; let it execute.                }                if (childCount > 1)                {                    // This target isn't a direct descendant and there are multiple                    // direct descendants; skip this target.                    e.Scope = sender;                    return;                }                else if (childCount == 1)                {                    // This target isn't a direct descendant, but we'll keep looking                    // down the descendants chain to see if it's a descendant of the                    // direct descendant.                    obj = VisualTreeHelper.GetChild(obj, 0) as DependencyObject;                }                else                {                    // End of the line; skip this target.                    e.Scope = sender;                    return;                }            }        }    }}


Unfortunately WPF has different behaviour to Win32 applications in this regard. I've come across this problem as well, as have a few others on the MSDN forums:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/91e031b7-091f-449d-9af2-f5fc3a071a45/

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/74f978b7-f445-4f4a-8416-57b38e04cb63/

Personally I think this is a bug in WPF, as it doesn't make a lot of sense.