Как я могу захватить событие KeyDown на странице WPF или объекте UserControl? - PullRequest
33 голосов
/ 07 декабря 2008

У меня есть страница с пользовательским контролем. Если пользователь нажимает клавишу Esc в любом месте страницы, которую я хочу обработать.

Я подумал, что это будет так же просто, как подключить событие PreviewKeyDown, проверить ключ Esc и затем обработать его. Однако, когда я установил точку останова в обработчике событий, я обнаружил, что она никогда не вызывается. Я подумал, что, возможно, UserControl может получить удар, поэтому я попробовал PreviewKeyDown там ... тот же результат.

Кто-нибудь знает правильное место для тестирования KeyDown или PreviewKeyDown на объекте Page?

Ответы [ 9 ]

34 голосов
/ 15 февраля 2013

Присоединить к событию окна

После загрузки элемента управления прикрепите к событию KeyDown окна (или любому событию), используя Window.GetWindow(this), например:

XAML

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

Код, стоящий за

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
}
26 голосов
/ 11 июня 2009

У меня / была такая же проблема. У меня есть окно, в котором размещается фрейм, который загружает / перемещается к различным страницам, которые в свою очередь содержат только 1 пользовательский элемент управления, который содержит обычные элементы управления / элементы (метки, гиперссылки и т. Д.).

то, что я обнаружил (конечно, после нескольких часов разочарования !!!), это то, что если вы НЕ сосредоточены на одном из элементов управления / элементов, упомянутых выше, событие PreviewKeyDown НЕ срабатывает в UserControl (останавливается где-то в кадре уровень), но как только вы помещаете фокус (например, вызывая ctrl.Focus () внутри обработчика события Loaded объекта UserCotrol) на одно из волшебных элементов управления, это срабатывает, событие запускается также для UserControl.

конечно, подумать об этом потом, это имеет смысл, но я на 100% уверен, что это застигнет врасплох, по крайней мере, 5 из 10 человек :) сумасшедшая штука под названием WPF ...

ура!

21 голосов
/ 07 декабря 2008

Я считаю, что событие PreviewKeyDown - это туннельное маршрутизируемое событие, а не пузырьковое. Если это так, то, если ваша страница не получает событие, пользовательский элемент управления не должен быть либо, так как он находится ниже страницы в визуальном дереве. Может быть, попытаться обработать его на верхнем уровне вашего приложения (возможно, Window?) И посмотреть, получает ли оно событие?

Другой вариант, который может помочь, - это использовать что-то вроде Snoop в CodePlex , чтобы выяснить, куда идут события.

12 голосов
/ 09 декабря 2011

Установка свойства Focusable в true на моем UserControl решила проблему для меня.

9 голосов
/ 16 сентября 2014

Я предлагаю метод, который усиливает упомянутый @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
}

Но это += рискованно, программист, скорее всего, забудет отменить регистрацию обработчика событий. Тогда произойдет утечка памяти или возникнут ошибки.

Здесь я предлагаю,

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 или YourUserControl.xaml.cs

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

Нет необходимости кодировать в xaml.

3 голосов
/ 09 марта 2014

Что именно сработало для меня:

Только в окне Загруженное событие прослушивание события 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!");   
}
1 голос
/ 11 октября 2016

У меня была похожая проблема при вызове окна WPF из WinForms. Ни KeyDown , ни PreviewKeyDown не сработало.

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

Однако, показывая окно как диалог , оно работало

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

PreviewKeyDown Событие сработало как заклинание для клавиш Escape и 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;
            }
        }

Надеюсь, это сработает.

0 голосов
/ 25 января 2019

Попробуйте включить ваше окно с ElementHost.EnableModelessKeyboardInterop. В моем случае это захват клавиш со стрелками в событии Keydown.

0 голосов
/ 03 января 2016

Это проверено и определенно работает.

  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 - это то, чего не хватает большинству людей. Думайте о PreviewKeyDown как об общем наблюдателе событий клавиатуры (но он не может повлиять на них, если я не ошибаюсь), и даже прослушивания KeyDown прослушиваются в пределах элемента управления или класса, в котором вы находитесь в настоящее время.

...