HandleAccessKeyPressed ( object sender, System.Windows.Input.AccessKeyPressedEventArgs e ) : void |
Fixes access key scoping bug within the WPF framework. 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 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. |
|