I would like to invoke a command using EventTrigger when a particular key is touched (for example, the spacebar key)
Currently I have:
I like the idea with a custom trigger but I didn't managed to make it work (some methods were changed or deprecated therefore the showed above definition of the SpaceKeyDownEventTrigger
is not compiled now). So, I put here the working version with custom RoutedEvent
instead. The SpaceKeyDownEvent
is defined in MyControl
custom control and is raised from the OnKeyDown
method when an unhandled KeyDown
attached event reaches MyControl
and the key pressed is the spacebar.
public class MyControl : ContentControl
{
// This constructor is provided automatically if you
// add a Custom Control (WPF) to your project
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyControl),
new FrameworkPropertyMetadata(typeof(MyControl)));
}
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent SpaceKeyDownEvent = EventManager.RegisterRoutedEvent(
"SpaceKeyDown",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(MyControl));
// Provide CLR accessors for the event
public event RoutedEventHandler SpaceKeyDown
{
add { AddHandler(SpaceKeyDownEvent, value); }
remove { RemoveHandler(SpaceKeyDownEvent, value); }
}
// This method raises the SpaceKeyDown event
protected virtual void RaiseSpaceKeyDownEvent()
{
RoutedEventArgs args = new RoutedEventArgs(SpaceKeyDownEvent);
RaiseEvent(args);
}
// Here KeyDown attached event is customized for the desired key
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Space)
RaiseSpaceKeyDownEvent();
}
}
The MyControl
could be added to the template of another control, allowing the latter to use EventTrigger
with the SpaceKeyDown
routed event:
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Grid>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Adding MyControl to the TextBox template -->
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<local:MyControl>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</local:MyControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="local:MyControl.SpaceKeyDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
From="White" To="Transparent" Duration="0:0:0.066" AutoReverse="True" RepeatBehavior="3x"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
You would have to build a custom Trigger to handle that:
public class SpaceKeyDownEventTrigger : EventTrigger {
public SpaceKeyDownEventTrigger() : base("KeyDown") {
}
protected override void OnEvent(EventArgs eventArgs) {
var e = eventArgs as KeyEventArgs;
if (e != null && e.Key == Key.Space)
this.InvokeActions(eventArgs);
}
}
Another approach would be to use KeyBindings and bind them to your Window, UserControl, FrameworkElement, etc. That will not Trigger a button, but say you have a command "MyCommand" that is called from the button, you could invoke the command from InputBindings.
<UserControl.InputBindings>
<KeyBinding Command="{Binding Path=ApplyCommand}" Key="Enter"/>
<KeyBinding Command="{Binding Path=NextPage}" Modifiers="Ctrl" Key="Left"/>
</UserControl.InputBindings>
<StackPanel>
<Button IsDefault="True" Content="Apply">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=ApplyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
You could also bind these KeyBindings to a TextBox.