如何将键盘输入命令绑定到主窗口? [英] How to bind keyboard input command to main window?

查看:107
本文介绍了如何将键盘输入命令绑定到主窗口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对WPF绑定比较陌生,并且在绑定ICommand实现的类(在窗口中检测用户键盘输入)时遇到困难?起初,我认为我需要将其绑定到XAML上的Window,但是,看来Window没有Command.

I am relatively new to WPF Binding, and having a difficulty in binding a ICommand implemented Class which is to detect user keyboard input in the window? At first I think I need to bind it to the Window on XAML, but, it appears that Window doesn't have Command.

这是我的ViewModel类

public class NoteBoxViewModel
{
    public MusicalNotation MusicalNotation { get; set; }
    public ICommand KeyboardHotkeyCommand { get; private set; }
    public bool IsSelected { get; set; }

    public NoteBoxViewModel()
    {
        MusicalNotation = new MusicalNotation();
        KeyboardHotkeyCommand = new KeyboardHotkeyCommand(this);
        IsSelected = true;
    }
}

这是我的KeyboardHotkeyCommand类

public class KeyboardHotkeyCommand : ICommand
{
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    private NoteBoxViewModel _vm;

    public KeyboardHotkeyCommand(NoteBoxViewModel vm)
    {
        _vm = vm;
    }

    public bool CanExecute(object parameter)
    {
        return _vm.IsSelected;
    }

    public void Execute(object parameter)
    {
        if (Keyboard.IsKeyDown(Key.OemPeriod))
        {
            _vm.MusicalNotation.Note = Notes.Blank;
        }
        else if (Keyboard.IsKeyDown(Key.D0))
        {
            _vm.MusicalNotation.Note = Notes.Rest;
        }
        else if (Keyboard.IsKeyDown(Key.D1))
        {
            _vm.MusicalNotation.Note = Notes.N1;
        }
        else if (Keyboard.IsKeyDown(Key.D2))
        {
            _vm.MusicalNotation.Note = Notes.N2;
        }
        else if (Keyboard.IsKeyDown(Key.D3))
        {
            _vm.MusicalNotation.Note = Notes.N3;
        }
        else if (Keyboard.IsKeyDown(Key.D4))
        {
            _vm.MusicalNotation.Note = Notes.N4;
        }
        else if (Keyboard.IsKeyDown(Key.D5))
        {
            _vm.MusicalNotation.Note = Notes.N5;
        }
        else if (Keyboard.IsKeyDown(Key.D6))
        {
            _vm.MusicalNotation.Note = Notes.N6;
        }
        else if (Keyboard.IsKeyDown(Key.D7))
        {
            _vm.MusicalNotation.Note = Notes.N7;
        }
        else if (Keyboard.Modifiers == ModifierKeys.Control && Keyboard.IsKeyDown(Key.OemPlus))
        {
            _vm.MusicalNotation.Octave++;
        }
        else if (Keyboard.Modifiers == ModifierKeys.Control && Keyboard.IsKeyDown(Key.OemMinus))
        {
            _vm.MusicalNotation.Octave--;
        }
    }
}

这是我的Notes枚举

public enum Notes
{
    N1,
    N2,
    N3,
    N4,
    N5,
    N6,
    N7,
    Rest,
    Blank
}

问题:

  1. 如何将KeyboardHotkeyCommand绑定到我的XAML类,以便我可以检测到用户输入(输入首先不进入Textbox或任何形式的文本编辑器)?我还尝试将其绑定到Window_IsKeyDown(我知道这是一种不好的做法),但毕竟失败了.如果没有event,是否可以实现?
  2. 在我的KeyboardHotkeyCommand中,有一个名为CanExecuteChanged的事件.我按照此处的指示填写了确切的方向: http://blog.lab49.com/archives/2650 .但是我不知道为什么会这样填满.有人可以向我解释吗?
  3. 我还在这里研究了该教程: http://reedcopsey.com/series/windows-forms-to-mvvm/,看来他可以用ActionCommand直接实例化ICommand,但是我在Visual Studio中找不到任何内容.有人知道为什么吗?
  1. How to bind KeyboardHotkeyCommand to my XAML Class so I can detect user input (input does not going to Textbox or any sort of text editor first)? I also tried to bind it to Window_IsKeyDown (it's a bad practice, I know) but it failed afterall. Is it possible to achieve it without event?
  2. In my KeyboardHotkeyCommand, there's an event named CanExecuteChanged. I filled it with exact direction with what is told here : http://blog.lab49.com/archives/2650. But I have no idea why it's filled that way. Can anyone explain to me?
  3. I also studied the tutorial here : http://reedcopsey.com/series/windows-forms-to-mvvm/ and it seems that he can directly instantiate the ICommand with ActionCommand, but I can't find any in my Visual Studio. Anyone knows why?

注意:

  1. 即使我不是MVVM的新手(昨天才知道),但我想使用尽可能多的MVVM模式,因此,我想避免使用事件(当然,如果可能的话),因为我读到它不是MVVM的好习惯.
  2. 我认为,无论我的MusicalNotation类是什么样子,它都不会影响此问题的解决,因为它只是一个模型".但是,如果需要的话,我也愿意100%向您展示.
  1. Even though I'm new to MVVM (just knew it yesterday), but I want to use as much as MVVM pattern as possible, so, I would like to avoid to use events (if that's possible, of course), since I read that it's not a good MVVM practice.
  2. I think, whatever my MusicalNotation class look like, it'll not affect the solution of this problem at all, since it's just a 'Model'. But if it's needed, I am 100% willing to show you as well.

推荐答案

使用MVVM模式,可以通过在主窗口上使用InputBindings将击键绑定到VM命令.样本Xaml片段看起来像这样...

Using the MVVM pattern, you can bind keystrokes to your VM commands by using the InputBindings on the Main Window. A sample Xaml snippet looks like this...

<Window.InputBindings>
    <KeyBinding Key="Right" Command="{Binding NavigateCommand}" CommandParameter="f"/>
    <KeyBinding Key="Left" Command="{Binding NavigateCommand}" CommandParameter="b"/>
    <KeyBinding Key="Delete"  Command="{Binding NavigateCommand}"  CommandParameter="delete"/>
    <KeyBinding Key="F5" Command="{Binding GetAllCommand}"/>
</Window.InputBindings>

KeyBinding类具有几个参数:键本身,它是一个枚举,以及诸如CTRL,ALT和SHIFT之类的任何修饰符.

The KeyBinding class takes several parameters: the key itself, which is an enumeration, along with any modifiers like CTRL, ALT, and SHIFT.

紧迫的两个参数是Command参数(绑定到VM)和CommandParameter(在命令委托中作为参数显示).

The two parameters of immediate interest are the Command parameter, which gets binded to the VM, and the CommandParameter, which appears as the argument in your command delegates.

在此示例中,Xaml将三个不同的击键绑定到NavigateCommand上,并使用CommandParameter让VM知道按下了哪个键.

In this example, the Xaml is binding three different keystrokes to the NavigateCommand and using the CommandParameter to let the VM know which key was pressed.

这里的InputBindings文档 http://msdn.microsoft.com/en-us/library/system.windows.input.inputbinding(v = vs.110).aspx ,其中包含更多用法示例.

The docs for InputBindings are here http://msdn.microsoft.com/en-us/library/system.windows.input.inputbinding(v=vs.110).aspx with more samples of usage.

注意:用法假定已将Window的DataContext设置为实现这些命令的VM实例,否则将出现数据绑定错误.

Note: the usage assumes that the DataContext of the Window has been set to the VM instance that implements these commands, otherwise there will be a data binding error.

您的实现看起来像这样...

Your implementation would look something like this...

<Window.InputBindings>
    <KeyBinding Key="A"  Command="{Binding KeyBoardHotKeyCommand}" CommandParameter="N1"/>
</Window.InputBindings>

使用ICommand代表...

With the ICommand delegates like...

    private void ExecuteKeyboardHotKeyCommand(object obj)
    {
        Notes note;
        if (obj!=null && Enum.TryParse(obj.ToString(), out note))
        {
            Console.WriteLine(@"User pressed {0}", note);
        }
    }
    private bool CanExecuteKeyboardHotKeyCommand(object obj)
    {
        return true;
    }

您的注释"枚举很好.您的ICommand代表沿着MVVM的正确方向前进,但由于无法轻松测试这些引用,因此需要从Keyboard.IsKeyDown中抽象出来.编写良好的视图模型与硬件无关,并且并不真正在乎事件是否发生在键盘或其他设备(如触摸屏)上.

Your 'Notes' enumeration is fine. Your ICommand delegates are along the right track for MVVM, but need to be abstracted away from Keyboard.IsKeyDown because these references cannot be easily tested. Well written View Models are hardware agnostic, and do not really care if the event occurred on the keyboard or some other device (like a touch screen).

对于您的最后一个问题,我使用乔什·史密斯(Josh Smith)的RelayCommand.看起来像这样...

For your last question, I use the Josh Smith's RelayCommand. It looks like this...

public class RelayCommand : ICommand
{   //http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }
    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;
}

CanExecuteChanged是WPF绑定引擎(或某些其他外部类)可以订阅的事件.一个实现看起来像这样……

CanExecuteChanged is an event that the WPF binding engine (or some other exogenous class) can subscribe to. An implementation looks like this...

    public ICommand KeyBoardHotKeyCommand { get; set; }
    public ViewModel()
    {
        KeyBoardHotKeyCommand = new RelayCommand(ExecuteKeyboardHotKeyCommand, CanExecuteKeyboardHotKeyCommand);
    }
    private void ExecuteKeyboardHotKeyCommand(object obj)
    {
        Notes note;
        if (obj!=null && Enum.TryParse(obj.ToString(), out note))
        {
            Console.WriteLine(@"User pressed {0}", note);
        }
    }
    private bool CanExecuteKeyboardHotKeyCommand(object obj)
    {
        return true;
    }

最后,对于您对Reed实施的疑问,Reed可能会在美国会员醒来时加入.但是目前,他的ActionCommand(现在是Expression Studio的一部分

Lastly, for your question about Reed's implementation, Reed will probably be along when members in the US wake up. But for the moment, his ActionCommand (now part of Expression Studio http://msdn.microsoft.com/en-us/library/microsoft.expression.interactivity.core.actioncommand(v=expression.40).aspx ) is fundamentally the same as Josh Smith's RelayCommand. They are all using the same principles to implement the ICommand interface.

这篇关于如何将键盘输入命令绑定到主窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆