How can I capture KeyDown event on a WPF Page or U

2019-01-05 03:31发布

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?

标签: wpf keydown
8条回答
爷、活的狠高调
2楼-- · 2019-01-05 03:58

This is tested and defintiely works.

  Private Sub textbox1_PreviewKeyDown(sender As Object, e As KeyEventArgs) Handles textbox1_input.PreviewKeyDown
        If (e.Key = Key.Down) Then
            MessageBox.Show("It works.")
        End If
    End Sub

'detect key state directly with something like this below
 Dim x As KeyStates = System.Windows.Input.Keyboard.GetKeyStates(Key.Down)

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.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-05 04:01

I had a similar issue when calling the WPF window out of WinForms. Neither KeyDown or PreviewKeyDown events were fired.

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.Show();

However, showing window as a dialog, it worked

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.ShowDialog();

PreviewKeyDown event fired like a charm for Escape and Arrow keys.

void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Escape:
                    this.Close();
                    break;
                case Key.Right:
                    page_forward();
                    break;
                case Key.Left:
                    page_backward();
                    break;
            }
        }

Hope this works.

查看更多
叛逆
4楼-- · 2019-01-05 04:02

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.

查看更多
迷人小祖宗
5楼-- · 2019-01-05 04:03

What exactly worked for me:

Only on window Loaded event listen to PreviewKeyDown event:

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!");   
}
查看更多
Evening l夕情丶
6楼-- · 2019-01-05 04:08

Attach to the Window's Event

After the control is loaded, attach to the Window's KeyDown event (or any event) by using Window.GetWindow(this), like so:

The XAML

<UserControl Loaded="UserControl_Loaded">
</UserControl>

The Code Behind

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
}
查看更多
乱世女痞
7楼-- · 2019-01-05 04:11

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. Once Window receives the KeyDown event bubbled from an inner element, Window triggers any KeyDown event-handler registered to it, like this 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
}

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

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);
}

YourUserControlViewModel.cs or YourUserControl.xaml.cs

public void CallKeyDown(KeyEventArgs e) {
  //Do your work
}

There is no need to code in xaml.

查看更多
登录 后发表回答