我有一个带有UserControl的页面。如果用户在我想要处理的页面上的任何位置按Esc。
我认为这就像挂钩PreviewKeyDown事件,测试Esc键,然后处理它一样简单。但是,当我在事件处理程序中放置断点时,我发现它永远不会被调用。我想也许UserControl可能会受到攻击,所以我尝试了那里的PreviewKeyDown ......结果相同。
有没有人知道在Page对象上测试KeyDown或PreviewKeyDown的正确位置?
答案 0 :(得分:34)
加载控件后,使用KeyDown
附加到Window的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 :(得分:26)
我有同样的问题。我有一个窗口,它承载一个框架,它加载/导航到各个页面,而这些页面只包含1个UserControl,其中包含正常的控件/元素(标签,超链接等)。
我发现的(当然经过几个小时的挫折!!!)是因为如果你没有关注上面提到的一个控件/元素,那么PreviewKeyDown事件就不会触发UserControl(在Frame的某处停止)等级)但是只要你将焦点(例如在UserCotrol的Loaded事件处理程序中调用ctrl.Focus())放在其中一个控件上就会发生魔法,它就会起作用,事件也会为UserControl触发。
当然,考虑到它后来这已经足够了,但我百分百肯定这将至少让10个人中的5个人惊讶:)疯狂的小东西叫WPF ......
喝彩!
答案 2 :(得分:21)
我相信PreviewKeyDown事件是隧道路由事件,而不是冒泡事件。如果是这种情况,那么如果您的页面没有获得该事件,则UserControl不应该是因为它位于可视树中的页面下方。也许尝试在应用程序的顶层处理它(可能是Window?)并查看它是否正在获取该事件?
另一个可能有用的选择是使用Snoop in CodePlex之类的东西来确定事件发生的位置。
答案 3 :(得分:12)
在我的UserControl上将Focusable属性设置为true为我解决了这个问题。
答案 4 :(得分:9)
我提出了一种强化所提到的@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
}
但是这个+=
是有风险的,程序员更可能忘记取消注册事件处理程序。然后会发生内存泄漏或一些错误。
我建议,
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);
}
public void CallKeyDown(KeyEventArgs e) {
//Do your work
}
无需在xaml中编码。
答案 5 :(得分:3)
究竟对我有用:
仅在窗口已加载的事件上收听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!");
}
答案 6 :(得分:1)
从WinForms调用WPF窗口时,我遇到了类似的问题。 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;
}
}
希望这有效。
答案 7 :(得分:1)
@Daniel解决方案的一种替代方案,它不需要您为整个Window添加事件处理程序,请执行以下操作:
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
}
}
这样,您可以在视图的不同部分具有相同事件的不同句柄。该句柄是本地的,特定于该控件,您无需向全局窗口添加句柄。
答案 8 :(得分:0)
尝试使用ElementHost.EnableModelessKeyboardInterop启用窗口。就我而言,它捕获Keydown事件中的箭头键。
答案 9 :(得分:0)
您可以简单地使用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 :(得分:0)
如果您不想附加到该窗口的事件,请添加一个事件以使您的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 :(得分:0)
我只是在视图中的按钮上调用 .Focus() 解决了这个问题,并确保窗口已完成所有元素的加载
答案 12 :(得分:-1)
经过测试,确定无误。
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。