如何从 WPF 中的子控件中获取键盘?

Posted

技术标签:

【中文标题】如何从 WPF 中的子控件中获取键盘?【英文标题】:How to grab keyboard from child controls in WPF? 【发布时间】:2011-04-19 02:32:08 【问题描述】:

我在一个窗口中有一些输入绑定:

<Window.InputBindings>
    <KeyBinding Key="Space" Command="Binding Path=StepNext" />
    <KeyBinding Key="R" Command="Binding Path=ResetSong" />
    <KeyBinding Key="Left" Command="Binding Path=StepPrevious" />             
</Window.InputBindings>

这些命令在我的视图模型中定义为 RelayCommands:

public class RelayCommand : ICommand

    private Action<object> _exec;
    private Func<object, bool> _canExec;

    public RelayCommand(Action<object> exec, Func<object, bool> canExec)
    
        _exec = exec;
        _canExec = canExec;
    

    public void Execute(object parameter)
    
        _exec(parameter);
    

    public bool CanExecute(object parameter)
    
        return _canExec(parameter);
    

    public event EventHandler CanExecuteChanged;

在 ViewModel 的构造函数中:

StepNext = new RelayCommand(DoStepNext, CanStepNext);

这很好用。但是,每当我在列表框中选择一个项目(它是 Window 的子项)时,KeyBindings 就会停止工作。无论哪个孩子有焦点(如果有),我如何让父母捕获键绑定。 (事件不应该冒泡吗?)

我知道有一个 PreviewKeyDown 事件可以做到这一点,但这会使我的ICommands 无用,所以如果可能的话,我更喜欢声明性解决方案。

提前致谢。

【问题讨论】:

【参考方案1】:

据我所知,没有任何声明方式可以让处理的事件继续冒泡。

如您所说,最简单的方法是处理Preview 事件。

作为替代方案,您可以像这样覆盖 ListBox 类 OnKeyDown 方法:

protected override void OnKeyDown(KeyEventArgs e)

    base.OnKeyDown(e);
    if (e.Key == Key.Space || e.Key == Key.Left)
        e.Handled = false;

【讨论】:

感谢您的回答,我添加了更多详细信息。我怀疑我的 ICommand 实现存在一些问题,但我不知道是什么问题。 我添加了这个事件处理程序,真正有趣的是它不会为三个绑定键(空格、左键和 R)触发。我很困惑。 它在我使用绑定到现有 ApplicationCommands.open 命令的示例项目中为我工作。三键响应正确。如果您愿意,我可以附加我的示例,但其中几乎没有其他内容。

以上是关于如何从 WPF 中的子控件中获取键盘?的主要内容,如果未能解决你的问题,请参考以下文章

WPF设置控件获取键盘焦点时的样式FocusVisualStyle

WPF虚拟键盘如何不获得当前焦点

WPF用键盘左右键按下获取按钮焦点,离开执行按钮事件

如何禁用所有 WPF 应用程序的虚拟键盘?

WPF学习第十六章 键盘输入

WPF学习第十六章 键盘输入