Как я могу запечатлеть событие keydown на странице WPF или пользовательский объект?
У меня есть страница с UserControl на ней. Если пользователь нажимает Esc в любом месте страницы, которую я хочу обработать.
Я думал, что это будет так же просто, как подключить событие PreviewKeyDown, протестировать ключ Esc, а затем обработать его. Однако, когда я поместил точку останова в обработчик событий, я обнаружил, что она никогда не вызывается. Я подумал, что, возможно, UserControl может быть поражен, поэтому я попытался PreviewKeyDown там... тот же результат.
Кто-нибудь знает подходящее место для тестирования для KeyDown или PreviewKeyDown на объекте страницы?
8 ответов:
Я считаю, что событие PreviewKeyDown является туннельным маршрутизируемым событием, а не пузырящимся. Если это так, то если ваша страница не получает событие, UserControl не должен быть ни тем, ни другим, так как он находится ниже страницы в визуальном дереве. Может быть, попробовать обработать его на верхнем уровне вашего приложения (окно, возможно?) и посмотреть, получает ли он событие?
Другим вариантом, который может помочь, было бы использовать что-то вроде Snoop в CodePlex , чтобы выяснить, где происходят события идущий.
Прикрепить к событию окна
После загрузки элемента управления присоедините к событию окна
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 }
У меня была / была та же проблема. У меня есть окно, которое содержит фрейм, который загружает / переходит на различные страницы, которые в свою очередь содержат только 1 UserControl, который содержит обычные элементы управления/элементы (метки, гиперссылки и т. д.).
То, что я обнаружил (после нескольких часов разочарования, конечно!!!) заключается в том, что если у вас нет фокуса на одном из элементов управления/элементов, упомянутых выше, событие PreviewKeyDown не срабатывает на UserControl (останавливается где-то на уровне фрейма), но как только вы поместите фокус (например, вызов ctrl.Focus () внутри загруженного обработчика событий UserCotrol) на одном из элементов управления magic происходит, он работает, событие срабатывает также для UserControl.
Конечно, думая об этом позже, это имеет достаточно смысла, но я на 100% уверен, что это будет удивлять по крайней мере 5 из 10 человек :) сумасшедшая маленькая вещь под названием WPF...
Ура!
Настройка фокусируемый свойству значение true на мой пользовательский элемент управления решена проблема для меня.
Я предлагаю метод, который усиливает тот, о котором упоминал @Doc.
Следующий код @Doc, упомянутый выше, будет работать, так как событие keydown routed передается на самый внешний
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 }Но это
+=рискованно, программист скорее всего забудет отменить регистрацию обработчика событий. Тогда утечка памяти или какие-то ошибки будут случаться.Здесь я предлагаю,
Ваше окно.код 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.
Что именно сработало для меня:
Только в окне загруженное событие Слушайте событие 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!"); }
У меня была аналогичная проблема при вызове окна 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; } }Надеюсь, это сработает.
Это проверено и определенно работает.
PreviewKeyDown-это то, чего не хватает большинству людей. Подумайте о PreviewKeyDown как об общем наблюдателе событий клавиатуры (но не может повлиять на них, если я не ошибаюсь), и даже KeyDown прослушиваются в пределах элемента управления или класса, в котором вы находитесь в данный момент.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)
Comments