web-dev-qa-db-fra.com

Comment capturer un événement KeyDown sur une page WPF ou un objet UserControl?

J'ai une page avec un UserControl dessus. Si l'utilisateur appuie sur Echap alors qu'il se trouve n'importe où sur la page, je souhaite le gérer.

Je pensais que cela serait aussi simple que de brancher l'événement PreviewKeyDown, de tester la touche Échap, puis de le gérer. Cependant, lorsque j'ai placé le point d'arrêt dans le gestionnaire d'événements, j'ai constaté qu'il n'était jamais appelé. Je pensais que le contrôle utilisateur pouvait être touché, alors j'ai essayé PreviewKeyDown là ... même résultat.

Est-ce que quelqu'un sait l'endroit approprié pour rechercher un objet KeyDown ou PreviewKeyDown sur un objet Page?

32
Sailing Judo

Je crois que l'événement PreviewKeyDown est un événement routé par tunneling, plutôt qu'un événement bouillonnant. Si tel est le cas, alors si votre page ne reçoit pas l'événement, UserControl ne doit pas l'être non plus, car il se trouve sous la page dans l'arborescence des visuels. Peut-être essayez-vous de le gérer au plus haut niveau de votre application (Windows peut-être?) Et voyez si l'événement est en train de se dérouler?

Une autre option qui pourrait aider serait d'utiliser quelque chose comme Snoop dans CodePlex pour déterminer où vont les événements.

21
Andy

Attacher à l'événement de la fenêtre

Une fois le contrôle chargé, attachez-le à l'événement KeyDown de la fenêtre (ou à un événement) à l'aide de Window.GetWindow(this), comme suit:

Le XAML

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

Le code derrière

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
}
33
Daniel

J'ai eu le même problème. J'ai une fenêtre qui héberge un cadre qui charge/navigue vers différentes pages qui, à leur tour, ne contiennent qu'un seul UserControl qui contient des contrôles/éléments normaux (étiquettes, liens hypertexte, etc.). 

ce que j’ai découvert (après quelques heures de frustration bien sûr !!!), c’est que si vous n’avez PAS le focus sur l’un des contrôles/éléments mentionnés ci-dessus, l’événement PreviewKeyDown ne se déclenche PAS sur UserControl (s’arrête quelque part au niveau Frame), mais dès que vous mettez le focus (par exemple, en appelant ctrl.Focus () à l'intérieur du gestionnaire d'événements Loaded de UserCotrol) sur l'un des contrôles qui se produisent, l'événement se déclenche également pour UserControl.

bien sûr, y penser par la suite, cela a du sens, mais je suis sûr à 100% que cela surprendra au moins 5 personnes sur 10 :) par une petite chose folle appelée WPF ...

à votre santé!

26
el_bibiq

La définition de la propriété Focusable sur true sur mon UserControl a résolu le problème pour moi.

12
Gigo

Je propose une méthode qui renforce celle mentionnée @Doc.

Le code suivant @Doc mentionné fonctionnera, car l'événement routé KeyDown est propulsé au Window le plus externe. Une fois que Window a reçu l'événement KeyDown diffusé à partir d'un élément interne, Window déclenche tout gestionnaire d'événements KeyDown enregistré, comme ceci 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
}

Mais ce += est risqué, un programmeur est plus susceptible d’oublier de désenregistrer le gestionnaire d’événements. Ensuite, des fuites de mémoire ou des bugs surviendront.

Ici je suggère,

VotreWindow.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 ou YourUserControl.xaml.cs

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

Il n'y a pas besoin de coder en xaml.

9
Jeff T.

Qu'est-ce qui a fonctionné exactement pour moi?

Uniquement dans la fenêtre Evénement chargé écouter l'événement 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!");   
}
3
alansiqueira27

J'ai eu un problème similaire lorsque j'ai appelé la fenêtre WPF à partir de WinForms. Ni les événements KeyDown ni PreviewKeyDown n'ont été déclenchés.

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

Cependant, montrer la fenêtre comme un dialogue , cela a fonctionné

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

L'événement PreviewKeyDown a été déclenché comme un charme pour les touches Escape et Arrow

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

J'espère que ça marche.

1
Janez Krnc

Essayez d'activer votre fenêtre avec ElementHost.EnableModelessKeyboardInterop. Dans mon cas, il capture les touches fléchées dans l'événement Keydown.

0
user340104