Подтвердить что ты не робот

Как я могу захватить событие KeyDown на странице WPF или объекте UserControl?

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Привязать к событию Window

После того, как элемент управления загружен, присоединитесь к событию Window 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
}

Ответ 3

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

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

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

ура!

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

У меня была аналогичная проблема при вызове окна 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;
            }
        }

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

Ответ 8

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

Ответ 9

Вы можете просто использовать событие Weindow_KeyDown.

вот пример

private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // ... Test for F1 key.
            if (e.Key == Key.F1)
            {
                this.Title = "You pressed F1 key";
            }
        }

не забудьте добавить атрибут Weindow_KeyDown в тег Window

<Window x:Class="WpfApplication25.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        KeyDown="Window_KeyDown">
</Window>

Ответ 10

Если вы не хотите прикреплять к окну событие, добавьте событие для видимых изменений вашего UserControl или Page:

IsVisibleChanged="Page_IsVisibleChanged"

Тогда в коде позади:

private void Page_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if(this.Visibility == Visibility.Visible)
            {
                this.Focusable = true;
                this.Focus();
            }
        }

Теперь ваше событие KeyDown будет запущено, если вы нажмете любую клавишу.

Ответ 11

Альтернативой решению @Daniel, которое не требует добавления обработчика событий для всего окна, является следующее:

public partial class MyControl : UserControl{

public MyControl()
{
   MouseEnter+= MouseEnterHandler;
   MouseLeave+= MouseLeaveHandler;
}

protected void MouseEnterHandler(object sender, MouseEventArgs e)
{
   var view = sender as MyControl;
   view.KeyDown += HandleKeyPress;
   view.KeyUp += HandleKeyReleased;
   view.Focus();
}

protected void MouseLeaveHandler(object sender, MouseEventArgs e)
{
   var view = sender as MyControl;
   view.KeyDown -= HandleKeyPress;
   view.KeyUp -= HandleKeyReleased;
}

protected void HandleKeyPress(object sender, KeyEventArgs e)
{
    // What happens on key pressed
}

protected void HandleKeyReleased(object sender, KeyEventArgs e)
{
    // What happens on key released
}

}

Таким образом, вы можете иметь разные дескрипторы одного и того же события в разных частях представления. Дескриптор является локальным и специфичным для элемента управления, вы не добавляете дескрипторы в глобальное окно.

Ответ 12

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

  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 evens прослушиваются в пределах контроля или класса, в котором вы сейчас находитесь.