wpf keyboard focus: losing focus after menu opens?
-
10-10-2019 - |
سؤال
This seems really easy, but it's definitely not working as expected. In WPF 4.0, I'm trying to create a window with a menu bar that accepts keyboard shortcuts... Just a simple window, a menu bar at the top, and some other stuff (inside AvalonDock, which may be part of the issue).
There's one catch: the menu bar & content are in another user control (let's call it SadPanda
, because it's making me a sad panda) that is the direct content of the window. The logical hierarchy looks something like this (not actual XAML):
<Window>
<UserControl x:Name="SadPanda" Focusable="True" FocusManager.IsFocusScope="True">
<Grid>
<MenuBar/>
<AvalonDock:DockingManager>
<PandaFood>
</AvalonDock:DockingManager>
</Grid>
</UserControl>
</Window>
The content of the window needs access to the window's Handle, so it's set after the window loads like this:
window.Loaded += delegate { window.Content = new SadPanda(); };
The menu bar & shortcuts have routed commands that are bound to SadPanda, and when the keyboard focus is lost, the input gestures no longer work, hence the sad panda. I added this:
LostKeyboardFocus += (sender, e) => Debug.WriteLine("Lost focus to " + e.NewFocus);
GotKeyboardFocus += (sender, e) => Debug.WriteLine("Got focus from " + e.OldFocus);
... and it seems that the focus is returning to the Window, rather than to SadPanda itself. If I set Focusable="False" on the window, then the focus goes to null; the control is never even considered. I tried (suggested by alpha-mouse in comments):
window.GotKeyboardFocus += delegate { Keyboard.Focus(sadPanda); };
Even this doesn't work -- it prevents menus from opening (they flash open for a second, then disappear) or text boxes from ever getting focus... Not sure why; it seems like the perfect solution.
Basically, I want the user control to have top-level keyboard focus, not the window. What's the easiest way to achieve this?
المحلول
I'm still not sure why this works, but here's the solution I found:
- Set
Focusable="False"
andFocusManager.IsFocusScope="False"
on the window. - Set
Focusable="True"
andFocusManager.IsFocusScope="True"
on the control.
Three. Use the following:
PleasedPanda.LostKeyboardFocus += (sender, e) =>
{
if(e.NewFocus == null)
{
Keyboard.Focus(PleasedPanda);
}
}
I'm not sure why this works while the more obvious window.GotKeyboardFocus
doesn't, but that's WPF for you.
نصائح أخرى
On the right of a hack. You can handle Window.GotKeyboardFocus
to immediately focus SadPanda
. But may be there are nicer solutions.