C# 如何将键盘输入命令绑定到主窗口?
我对WPF绑定比较陌生,在绑定C# 如何将键盘输入命令绑定到主窗口?,c#,wpf,mvvm,keyboard,icommand,C#,Wpf,Mvvm,Keyboard,Icommand,我对WPF绑定比较陌生,在绑定ICommand实现的类(用于检测窗口中的用户键盘输入)时遇到困难?起初,我认为需要将它绑定到XAML上的窗口,但该窗口似乎没有命令 这是我的ViewModel类 public class NoteBoxViewModel { public MusicalNotation MusicalNotation { get; set; } public ICommand KeyboardHotkeyCommand { get; private set; }
ICommand
实现的类(用于检测窗口中的用户键盘输入)时遇到困难?起初,我认为需要将它绑定到XAML上的窗口,但该窗口似乎没有命令
这是我的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;
}
}
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--;
}
}
}
这是我的KeyboardHotkeyCommand类
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;
}
}
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--;
}
}
}
这是我的笔记枚举
public enum Notes
{
N1,
N2,
N3,
N4,
N5,
N6,
N7,
Rest,
Blank
}
问题:
如何将KeyboardHotkeyCommand
绑定到我的XAML类,以便检测用户输入(input不会首先进入Textbox
或任何类型的文本编辑器)?我还尝试将它绑定到窗口_IsKeyDown
(我知道这是一个糟糕的做法),但最终失败了。是否可以在没有事件的情况下实现它
在我的KeyboardHotkeyCommand
中,有一个名为CanExecuteChanged
的事件。我在上面填上了确切的方向,上面说的是:。但我不知道为什么会这样。谁能给我解释一下吗
我还研究了这里的教程:他似乎可以用ActionCommand
直接实例化ICommand
,但在我的VisualStudio中找不到。有人知道为什么吗
注:
尽管我是MVVM新手(昨天才知道),但我希望尽可能多地使用MVVM模式,因此,我希望避免使用事件(当然,如果可能的话),因为我读到这不是一个好的MVVM实践
我认为,无论我的MusicalNotation
类是什么样子,它都不会影响这个问题的解决,因为它只是一个“模型”。但如果需要的话,我也会百分之百地向你展示
使用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>
<Window.InputBindings>
<KeyBinding Key="A" Command="{Binding KeyBoardHotKeyCommand}" CommandParameter="N1"/>
</Window.InputBindings>
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;
}
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;
}
使用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;
}
您的“Notes”枚举很好。您的ICommand
代理在MVVM方面走的是正确的道路,但需要从Keyboard.IsKeyDown中抽象出来,因为这些引用不容易测试。写得好的视图模型与硬件无关,并不真正关心事件是否发生在键盘或其他设备(如触摸屏)上
对于最后一个问题,我使用Josh Smith的RelayCommand
。看起来像这样
<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>
<Window.InputBindings>
<KeyBinding Key="A" Command="{Binding KeyBoardHotKeyCommand}" CommandParameter="N1"/>
</Window.InputBindings>
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;
}
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的一部分
)基本上与Josh Smith的
RelayCommand
相同。它们都使用相同的原则来实现ICommand
接口。如果可能,请您也回答第2个问题好吗?第2个和第3个问题已修改如果可能,您能否进一步解释一下:添加{CommandManager.RequerySuggested+=value;}
和删除{CommandManager.RequerySuggested-=value;}
?谢谢。你能读一下吗?如果有什么不清楚的地方,那就形成另一个问题?我有。嗯。那么,value是要绑定的元素吗?如果是,那我就有点明白了。