在特定按键上使用EventTrigger

14

我希望通过EventTrigger在按下特定键(例如空格键)时调用一个命令。

目前我有以下代码:

  <i:Interaction.Triggers>
       <i:EventTrigger EventName="KeyDown">
            <i:InvokeCommandAction Command="{Binding DoCommand}" CommandParameter="{BindingText}"/>
       </i:EventTrigger>
  </i:Interaction.Triggers>

现在我该如何指定只有在按下空格键时才发生这种情况?

3个回答

15

您需要构建一个自定义触发器来处理这个问题:

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);
    }
}

谢谢您的回复,但我仍然无法使其工作。我将我的XAML更改为使用SpaceKeyDownEventTrigger(而不仅仅是EventTrigger),但OnEvent没有被触发。在我的XAML中还有其他需要更改的吗?再次感谢。 - lost_bits1110
@lost_bits1110 - 你能否更新你的问题并包含一个完整的示例?你确定KeyDown事件是否对应的控件触发了吗? - CodeNaked
是的,在我的原始帖子中,事件正在为关联控件触发,但是在每个按键事件中都会发生。我希望它只在指定的键上发生。我添加了一个自定义的EventTrigger类,就像您发布的那样,并简单地更改了我的XAML,将EventTrigger替换为SpakeKeyDownEventTrigger,但看起来我需要更多的东西。 - lost_bits1110
好的,现在可以工作了 - 我的错误是我忘记加上“override”关键字。谢谢! - lost_bits1110
@lost_bits1110 - 啊,是的,我最初也有那个,但之前纠正了我的错误。 - CodeNaked
太棒了。由于使用InputBindings的传统方法似乎无法在DatePicker控件中处理“Enter Pressed”事件,因此我一直在使用这种方法。使用这种方法使我能够绕过这个明显的限制。 - AndyUK

15
另一种方法是使用KeyBindings,并将其绑定到您的Window、UserControl、FrameworkElement等。 这不会触发按钮,但是假设您有一个从按钮调用的命令"MyCommand",则可以通过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>

您也可以将这些KeyBindings绑定到TextBox上。


1
我更喜欢这种解决方案,因为它允许我将几乎所有的代码都保留在XAML中以处理关键交互。我目前正在开发一个TextBlock/TextBox可编辑标签,并且以这种方式进行可以让我创建一个新的可编辑样式,可以应用于任何标签。简单而优雅。谢谢Kalisohn! - James McDuffie
这对我有用。我正在为“+”和“-”符号创建触发器。接受我的赞美! - tCoe

1
我喜欢使用自定义触发器的想法,但我没能使其工作(由于一些方法已更改或废弃,因此上面显示的SpaceKeyDownEventTrigger定义现在无法编译)。因此,我在这里提供了具有自定义RoutedEvent的可工作版本。 SpaceKeyDownEventMyControl自定义控件中定义,并且当未处理的KeyDown附加事件到达MyControl并且按下的键是空格键时,从OnKeyDown方法中引发。
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();
    }
}

"

MyControl 可以添加到另一个控件的模板中,使得后者可以使用 EventTriggerSpaceKeyDown 路由事件:

"
<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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接