如何在WPF页面或UserControl对象上捕获KeyDown事件?

Sai*_*udo 34 wpf keydown

我有一个带有UserControl的页面.如果用户在我想要处理的页面上的任何位置按Esc.

我认为这就像挂钩PreviewKeyDown事件,测试Esc键,然后处理它一样简单.但是,当我在事件处理程序中放置断点时,我发现它永远不会被调用.我想也许UserControl可能会被击中,所以我尝试了PreviewKeyDown ......结果相同.

有没有人知道在Page对象上测试KeyDown或PreviewKeyDown的正确位置?

Dan*_*iel 38

附加到窗口的事件

加载控件后,使用如下所示附加到Window的KeyDown事件(或任何事件)Window.GetWindow(this):

XAML

<UserControl Loaded="UserControl_Loaded">
</UserControl>
Run Code Online (Sandbox Code Playgroud)

守则背后

private void UserControl_Loaded(object sender, RoutedEventArgs e) {
  var window = Window.GetWindow(this);
  window.KeyDown += HandleKeyPress;
}

private void HandleKeyPress(object sender, KeyEventArgs e) {
  //Do work
}
Run Code Online (Sandbox Code Playgroud)

  • 我需要仔细检查一下,但是我大脑的偏执部分说你应该在卸下控件时取消绑定事件.否则,您将保留从UserControl到其托管的Window对象的链接,并且它们永远不会被释放(以内存方式). (10认同)

小智 26

我曾经有过同样的问题.我有一个窗口,它承载一个框架,它加载/导航到各个页面,而这些页面只包含1个UserControl,其中包含正常的控件/元素(标签,超链接等).

我发现的(当然是经过几个小时的挫折!!!)是因为如果你没有关注上面提到的一个控件/元素,那么PreviewKeyDown事件不会触发UserControl(在Frame级别的某处停止)但是一旦你将焦点(例如在UserCotrol的Loaded事件处理程序中调用ctrl.Focus())放在其中一个控件上,就会发生魔法,它会起作用,事件也会为UserControl触发.

当然,考虑到它后来这已经足够了但我100%肯定这将至少让10个人中的5个惊讶:)疯狂的小东西叫WPF ...

干杯!

  • 当您尝试对焦时,不要忘记在已加载的页面/控件上设置focusable属性. (4认同)

And*_*ndy 21

我相信PreviewKeyDown事件是隧道路由事件,而不是冒泡事件.如果是这种情况,那么如果您的页面没有获得该事件,则UserControl不应该是因为它位于可视树中的页面下方.也许尝试在应用程序的顶层处理它(可能是Window?)并查看它是否正在获取该事件?

另一个可能有用的选择是在CodePlex中使用Snoop之类的东西来确定事件发生的位置.


Gig*_*igo 12

在我的UserControl上将Focusable属性设置为true为我解决了这个问题.


Jef*_* T. 9

我提出了一种加强所提到的@Doc的方法.

提到的以下代码@Doc将起作用,因为KeyDown路由事件被冒泡到最外面Window.一旦Window收到从内部元素冒泡的KeyDown事件,Window就会触发注册到它的任何KeyDown事件处理程序,就像这样HandleKeyPress.

private void UserControl_Loaded(object sender, RoutedEventArgs e) {
  var window = Window.GetWindow(this);
  window.KeyDown += HandleKeyPress;
}

private void HandleKeyPress(object sender, KeyEventArgs e) {
  //Do work
}
Run Code Online (Sandbox Code Playgroud)

但这+=有风险,程序员更可能忘记取消注册事件处理程序.然后内存泄漏或一些错误将发生.

在这里我建议,

YourWindow.xaml.cs

protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);

    // You need to have a reference to YourUserControlViewModel in the class.
    YourUserControlViewModel.CallKeyDown(e);

    // Or, if you don't like ViewModel, hold your user-control in the class then
    YourUserControl.CallKeyDown(e);
}
Run Code Online (Sandbox Code Playgroud)

YourUserControlViewModel.cs或YourUserControl.xaml.cs

public void CallKeyDown(KeyEventArgs e) {
  //Do your work
}
Run Code Online (Sandbox Code Playgroud)

无需在xaml中编码.


ala*_*a27 5

什么对我有用:

仅在窗口Loaded 事件上监听 PreviewKeyDown 事件:

void GameScreen_Loaded(object sender, RoutedEventArgs e)
{
     this.PreviewKeyDown += GameScreen_PreviewKeyDown;
     this.Focusable = true;
     this.Focus();
}

void GameScreen_PreviewKeyDown(object sender, KeyEventArgs e)
{
     MessageBox.Show("it works!");   
}
Run Code Online (Sandbox Code Playgroud)