我对WPF Binding相对较新,并且难以绑定ICommand
实现的Class,以检测窗口中的用户键盘输入?起初我认为我需要将它绑定到XAML上的Window,但是,看起来Window没有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 Class
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
}
问题:
KeyboardHotkeyCommand
绑定到我的XAML类,以便检测用户输入(输入不会Textbox
或任何类型的文本编辑器)?我也尝试将它绑定到Window_IsKeyDown
(这是一个不好的做法,我知道),但它毕竟失败了。是否有可能在没有event
?KeyboardHotkeyCommand
中,有一个名为CanExecuteChanged
的事件。我在这里告诉我的确切方向:http://blog.lab49.com/archives/2650。但我不知道为什么它会这样填充。谁能向我解释一下?ICommand
直接实例化ActionCommand
,但我在Visual Studio中找不到任何内容。谁知道为什么?注意:
MusicalNotation
类看起来如何,它都不会影响这个问题的解决方案,因为它只是一个'模型'。但如果需要,我也愿意为你展示。答案 0 :(得分:3)
使用MVVM模式,您可以使用主窗口上的InputBindings
将键击绑定到VM命令。示例Xaml
代码段看起来像这样......
<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。
直接感兴趣的两个参数是Command
参数,它被绑定到VM,以及CommandParameter
,它在命令代理中显示为参数。
在此示例中,Xaml
将三个不同的击键绑定到NavigateCommand,并使用CommandParameter
让VM知道按下了哪个键。
InputBindings的文档在这里http://msdn.microsoft.com/en-us/library/system.windows.input.inputbinding(v=vs.110).aspx有更多的使用样本。
注意:用法假定Window的DataContext
已设置为实现这些命令的VM实例,否则将出现数据绑定错误。
你的实现看起来像这样......
<Window.InputBindings>
<KeyBinding Key="A" Command="{Binding KeyBoardHotKeyCommand}" CommandParameter="N1"/>
</Window.InputBindings>
与ICommand代表一样......
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;
}
你的笔记&#39;枚举很好。您的ICommand
代表是MVVM的正确轨道,但需要从Keyboard.IsKeyDown
抽象出来,因为这些引用无法轻松测试。写得很好的视图模型是硬件无关的,并不关心事件是否发生在键盘或其他设备(如触摸屏)上。
关于你的上一个问题,我使用的是Josh Smith的RelayCommand
。它看起来像这样......
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绑定引擎(或其他一些外源类)可以订阅的事件。实现看起来像这样......
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 http://msdn.microsoft.com/en-us/library/microsoft.expression.interactivity.core.actioncommand(v=expression.40).aspx的一部分
)与Josh Smith的RelayCommand
基本相同。他们都使用相同的原则来实现ICommand
接口。