不会触发 KeyDown 事件,但会触发与 PreviewMouseLeftButtonDown 事件完全相同的代码
The KeyDown event will not fire, but the exact same code with PreviewMouseLeftButtonDown event will
我目前正在使用 WPF 创建一个需要按键的简单小游戏。我用鼠标点击做了类似的事情,但我正在努力使用按键。我搜索了很长时间,发现使用键的最常用方法是为自己的事件定义每个键。但这不是我的情况,我希望它能够在每次按下任何键时触发它。我发现这可以通过 MVVMLight 和 EventToCommand 来完成,但由于某些我不知道的原因,KeyDown 事件不会触发(更晚的 KeyUp),但 PreviewMouseLeftButtonDown 会触发。
xaml 文件:
<i:Interaction.Triggers>
// will not fire
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will not fire
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will fire
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
视图模型:
public DelegateCommand onKeyDown
{
get
{
MessageBox.Show("Down");
return new DelegateCommand(() => MessageBox.Show("Down"));
}
}
(完整 xaml 文件)
<UserControl x:Class=".......AsteroidsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="{DynamicResource ThemeBackgroundColor}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source=".......Module.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="100" />
<RowDefinition Height="200*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"
Style="{StaticResource ReturnBackButtonStyle}"
Command="{Binding ReturnFromSearchingCommand, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="Game"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="2"
Text="Controls"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Canvas Grid.Row="2" Grid.Column="1"
Background="LightBlue"
Name="MyCanvas"
Focusable="True">
<Rectangle Name="player" Height="50" Width="60" Fill="Yellow" Canvas.Left="222" Canvas.Top="495"/>
<Label Name="scoreText" Content="Score: 0" FontSize="18" FontWeight="Bold" Foreground="White"/>
<Label Name="damageText" Content="Damage: 0" FontSize="18" FontWeight="Bold" Canvas.Right="0" Foreground="White"/>
</Canvas>
</Grid>
</UserControl>
提前致谢!
编辑 + 更新 1:
我试过强迫它,但我发现了一些奇怪的东西。
<UserControl.InputBindings>
<KeyBinding Key="Delete"
Command="{Binding onKeyDown, Mode=OneWay}" />
</UserControl.InputBindings>
使用上面的代码,我仍然无法触发 onKeyDown
事件。我不知道为什么,但我认为它在代码中更深入
有一个 PreviewKeyDown
活动您可以试试。它不适用于 KeyDown
和 MouseDown
的最常见原因是控件已经在内部处理按键和鼠标交互。
PreviewKeyDown
事件只会在控件获得焦点时触发,因此您还必须将 UserControl
的 Focusable
属性 设置为 true
.
确保始终捕获 UserControl
中的按键的更好方法是以编程方式处理父级 window 的按键事件:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
//TODO: handle...
}
}
以防万一有人需要“处理”部分,我注意到我遇到的核心问题是我有一个不同的 window 重点。所以,我所做的是将键盘聚焦到我需要的 Canvas,这些事件就像一个魅力。这是一个代码:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
Keyboard.Focus(this.MyCanvas); // `this` keyword is redundant
}
}
所以,mm8给出了正确的解决方案,对我来说就是少了这么一小块拼图。这个谜题的缺失部分是在这里找到的 -> https://social.msdn.microsoft.com/Forums/vstudio/en-US/20d7dc78-53a0-494a-a3cc-b463a23b8196/keydown-does-not-get-fired-up?forum=wpf 我注意到你需要有你想要使用的元素 focused
和 visible
我目前正在使用 WPF 创建一个需要按键的简单小游戏。我用鼠标点击做了类似的事情,但我正在努力使用按键。我搜索了很长时间,发现使用键的最常用方法是为自己的事件定义每个键。但这不是我的情况,我希望它能够在每次按下任何键时触发它。我发现这可以通过 MVVMLight 和 EventToCommand 来完成,但由于某些我不知道的原因,KeyDown 事件不会触发(更晚的 KeyUp),但 PreviewMouseLeftButtonDown 会触发。
xaml 文件:
<i:Interaction.Triggers>
// will not fire
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will not fire
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will fire
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
视图模型:
public DelegateCommand onKeyDown
{
get
{
MessageBox.Show("Down");
return new DelegateCommand(() => MessageBox.Show("Down"));
}
}
(完整 xaml 文件)
<UserControl x:Class=".......AsteroidsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="{DynamicResource ThemeBackgroundColor}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source=".......Module.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="100" />
<RowDefinition Height="200*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"
Style="{StaticResource ReturnBackButtonStyle}"
Command="{Binding ReturnFromSearchingCommand, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="Game"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="2"
Text="Controls"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Canvas Grid.Row="2" Grid.Column="1"
Background="LightBlue"
Name="MyCanvas"
Focusable="True">
<Rectangle Name="player" Height="50" Width="60" Fill="Yellow" Canvas.Left="222" Canvas.Top="495"/>
<Label Name="scoreText" Content="Score: 0" FontSize="18" FontWeight="Bold" Foreground="White"/>
<Label Name="damageText" Content="Damage: 0" FontSize="18" FontWeight="Bold" Canvas.Right="0" Foreground="White"/>
</Canvas>
</Grid>
</UserControl>
提前致谢!
编辑 + 更新 1:
我试过强迫它,但我发现了一些奇怪的东西。
<UserControl.InputBindings>
<KeyBinding Key="Delete"
Command="{Binding onKeyDown, Mode=OneWay}" />
</UserControl.InputBindings>
使用上面的代码,我仍然无法触发 onKeyDown
事件。我不知道为什么,但我认为它在代码中更深入
有一个 PreviewKeyDown
活动您可以试试。它不适用于 KeyDown
和 MouseDown
的最常见原因是控件已经在内部处理按键和鼠标交互。
PreviewKeyDown
事件只会在控件获得焦点时触发,因此您还必须将 UserControl
的 Focusable
属性 设置为 true
.
确保始终捕获 UserControl
中的按键的更好方法是以编程方式处理父级 window 的按键事件:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
//TODO: handle...
}
}
以防万一有人需要“处理”部分,我注意到我遇到的核心问题是我有一个不同的 window 重点。所以,我所做的是将键盘聚焦到我需要的 Canvas,这些事件就像一个魅力。这是一个代码:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
Keyboard.Focus(this.MyCanvas); // `this` keyword is redundant
}
}
所以,mm8给出了正确的解决方案,对我来说就是少了这么一小块拼图。这个谜题的缺失部分是在这里找到的 -> https://social.msdn.microsoft.com/Forums/vstudio/en-US/20d7dc78-53a0-494a-a3cc-b463a23b8196/keydown-does-not-get-fired-up?forum=wpf 我注意到你需要有你想要使用的元素 focused
和 visible