如何捕获 WPF 页面或 UserControl 对象上的 KeyDown 事件?
我有一个带有用户控件的页面。 如果用户在我想要处理的页面上的任何位置按 Esc。
我认为这就像连接 PreviewKeyDown 事件、测试 Esc 键然后处理它一样简单。 然而,当我在事件处理程序中放置断点时,我发现它永远不会被调用。 我想也许 UserControl 可能会受到攻击,所以我在那里尝试了 PreviewKeyDown...相同的结果。
有谁知道在 Page 对象上测试 KeyDown 或 PreviewKeyDown 的正确位置?
I have a Page with a UserControl on it. If the user presses Esc while anywhere on Page I want to handle.
I thought this would be as easy as hooking up the PreviewKeyDown event, testing for the Esc key, and then handling it. However, when I placed I breakpoint in the event handler I found it was never getting called. I thought perhaps the UserControl might be getting hit, so I tried PreviewKeyDown there... same result.
Does anyone know the proper place to test for a KeyDown or PreviewKeyDown on a Page object?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
附加到窗口的事件
加载控件后,使用
Window.GetWindow(this)
附加到窗口的KeyDown
事件(或任何事件),如下所示: >XAML
背后的代码
Attach to the Window's Event
After the control is loaded, attach to the Window's
KeyDown
event (or any event) by usingWindow.GetWindow(this)
, like so:The XAML
The Code Behind
我曾经也有过一样的问题。 我有一个窗口,其中托管一个框架,该框架加载/导航到各个页面,而这些页面又只包含 1 个用户控件,其中包含普通控件/元素(标签、超链接等)。
我发现(当然是经过几个小时的挫折!!!)是,如果您没有将注意力集中在上面提到的控件/元素之一上,则 PreviewKeyDown 事件不会在 UserControl 上触发(在帧级别的某个位置停止),但是一旦您将焦点(例如在 UserCotrol 的 Loaded 事件处理程序中调用 ctrl.Focus() )放在其中一个控件上,魔法就会发生,它会起作用,该事件也会为 UserControl 触发。
当然,事后想一想,这很有道理,但我 100% 确定这会让至少十分之五的人感到惊讶:) 名为 WPF 的疯狂小东西......
干杯!
I have/had the same problem. I have a window which hosts a Frame which loads/navigates to various Page's which at their turn contain just 1 UserControl which contains normal Controls/Elements (Labels, Hyperlinks, etc).
what I discovered (after some hours of frustration of course!!!) is that if you do NOT have the focus on one of the Controls/Elements mentioned above the PreviewKeyDown event does NOT fire on the UserControl (stops somewhere at Frame level) but as soon as you put the focus (for instance calling ctrl.Focus() inside the UserCotrol's Loaded event handler) on one of the controls magic happens, it works, the event fires also for the UserControl.
of course thinking of it afterwards this makes enough sense but I am 100% sure this will cacth at least 5 out of 10 people by surprise :) crazy little thing called WPF...
cheers!
我相信 PreviewKeyDown 事件是一种隧道路由事件,而不是冒泡事件。 如果是这种情况,那么如果您的页面没有收到该事件,则 UserControl 也不应该收到该事件,因为它位于可视化树中页面的下方。 也许尝试在应用程序的顶层处理它(也许是窗口?),看看它是否正在获取事件?
另一个可能有帮助的选择是使用 Snoop in CodePlex 之类的东西来找出事件的去向。
I believe that the PreviewKeyDown event is a tunneling routed event, rather than a bubbling one. If that is the case, then if your Page isn't getting the event, the UserControl shouldn't be either since it is below the Page in the visual tree. Maybe try handling it at the top level of your app (Window perhaps?) and see if it is getting the event?
Another option that might help would be to use something like Snoop in CodePlex to figure out where the events are going.
将我的 UserControl 上的 Focusable 属性设置为 true 解决了我的问题。
Setting the Focusable property to true on my UserControl solved the issue for me.
我提出了一种加强@Doc提到的方法。
@Doc 提到的以下代码将起作用,因为 KeyDown 路由事件被冒泡到最外面的 Window 。 一旦
Window
接收到从内部元素冒出的 KeyDown 事件,Window
就会触发向其注册的任何 KeyDown 事件处理程序,例如HandleKeyPress
。但是这个
+=
是有风险的,程序员更有可能忘记取消注册事件处理程序。 那么就会发生内存泄漏或者一些错误。这里我建议,
YourWindow.xaml.cs
YourUserControlViewModel.cs 或 YourUserControl.xaml.cs
不需要在xaml中编码。
I propose a method which strengthens the one @Doc mentioned.
The following code @Doc mentioned will work since the KeyDown routed event is bubbled to the outermost
Window
. OnceWindow
receives the KeyDown event bubbled from an inner element,Window
triggers any KeyDown event-handler registered to it, like thisHandleKeyPress
.But this
+=
is risky, a programmer is more likely to forget to un-register the event-handler. Then memory leaking or some bugs will happen.Here I suggest,
YourWindow.xaml.cs
YourUserControlViewModel.cs or YourUserControl.xaml.cs
There is no need to code in xaml.
到底什么对我有用:
仅在窗口 Loaded 事件 上监听 PreviewKeyDown 事件:
What exactly worked for me:
Only on window Loaded event listen to PreviewKeyDown event:
如果您不想附加到窗口的事件,请添加一个事件以对您的 UserControl 或 Page 进行可见更改:
然后在后面的代码中:
现在,如果您按任意键,您的事件 KeyDown 将被触发。
If you don't want to attach to the window's event, add an event for visible changed of your UserControl or Page:
Then in code behind:
Now your event KeyDown would be fired if you press any key.
从 WinForms 调用 WPF 窗口时,我遇到了类似的问题。 KeyDown 或 PreviewKeyDown 事件均未触发。
但是,将窗口显示为对话框时,它
可以像Escape和箭头键一样触发PreviewKeyDown事件。
希望这有效。
I had a similar issue when calling the WPF window out of WinForms. Neither KeyDown or PreviewKeyDown events were fired.
However, showing window as a dialog, it worked
PreviewKeyDown event fired like a charm for Escape and Arrow keys.
Hope this works.
@Daniel 解决方案的替代方案不需要您为整个窗口添加事件处理程序,而是执行以下操作:
这样您就可以在视图的不同部分中拥有同一事件的不同句柄。 句柄是本地的且特定于控件,您不需要将句柄添加到全局窗口。
An alternative to the solution of @Daniel, that doesn't require you to add an event handler for the entire Window, is to do the following:
This way you can have different handles of the same event in different parts of the view. The handle is local and specific to the control, you don't add handles to the global window.
您只需使用
Window_KeyDown
事件即可。这是一个示例:
不要忘记将
Window_KeyDown
属性添加到 Window 标记You can simply use the
Window_KeyDown
event.Here is an example:
Don't forget to add the
Window_KeyDown
attribute to the Window tag尝试使用 ElementHost.EnableModelessKeyboardInterop 启用窗口。 就我而言,它捕获 Keydown 事件中的箭头键。
Try enabling your window with ElementHost.EnableModelessKeyboardInterop. In my case it capture arrow keys in the Keydown event.
我修复了这个问题,只需在视图中的按钮上调用 .Focus() 并确保窗口已完成所有元素的加载
I fixed this issue just calling .Focus() on a button in the view and make sure the the window has finished the loading of all elements
您的 UserControl 有一个初始值设定项。 将处理程序添加到该代码后面。 无需在 XAML 中执行任何操作。
您不需要 onload 事件。 这包含在初始化程序中。 将所有内容保存在一个文件中将使维护变得更加容易。
正如其他人提到的,PreviewKeyDown 可能比 KeyDown 更适合您,具体取决于您的需求。
Your UserControl has an initializer. Add the handler to that code behind. No need to do anything in XAML.
You don't need an onload event. That's included in the initializer. And keeping everything in one file will make maintaining it easier.
As others have mentioned, PreviewKeyDown might serve you better than KeyDown, depending on your needs.
这是经过测试并且肯定有效的。
PreviewKeyDown 是大多数人错过的。 将 PreviewKeyDown 视为键盘事件的整体观察者(但如果我没有弄错的话,则不会影响它们)并且 KeyDown 事件正在您当前所在的控件或类的范围内被监听。
This is tested and defintiely works.
PreviewKeyDown is what most people miss. Think of PreviewKeyDown as an overall observer of keyboard events, (but cannot effect them if im not mistaken) and KeyDown evens are being listened to within the confines of the control or class you are currently in.