Ответ 1
Свойство Command класса KeyBinding не поддерживает привязку данных. Эта проблема будет решена в .NET 4.0, и вы сможете увидеть ее в следующей версии .NET 4.0 Beta 2.
Я использую RelayCommand в своем приложении. Это отлично подходит для ввода кода в viewmodel, но как мне привязать нажатия клавиш к моей команде?
RoutedUICommand имеет свойство InputGestures, что делает команду автоматически вызываться при нажатии клавиши. (В качестве дополнительного бонуса он даже делает отображение нажатия клавиши в MenuItem.) К сожалению, нет никакого многоразового интерфейса для RoutedUICommand дополнительных свойств, поэтому я не могу сделать RelayUICommand, который получает ту же магию.
Я уже пробовал использовать InputBindings:
<Window.InputBindings>
<KeyBinding Key="PageUp" Command="{Binding SelectPreviousLayerCommand}"/>
</Window.InputBindings>
Но это дает мне исключение во время выполнения, потому что KeyBinding.Command не является свойством зависимостей. (На самом деле, о чем он жалуется, является то, что KeyBinding не является также DependencyObject.) И поскольку мой RelayCommand является свойством в моей модели ViewModel (в отличие от статического поля, для которого предназначен RoutedUICommand), привязка данных - единственный способ, которым я знаю ссылаться на него из XAML.
Как вы, ребята, решили это? Какой лучший способ привязать нажатие клавиши к RelayCommand?
Свойство Command класса KeyBinding не поддерживает привязку данных. Эта проблема будет решена в .NET 4.0, и вы сможете увидеть ее в следующей версии .NET 4.0 Beta 2.
Я не думаю, что вы можете сделать это из XAML, точно по причинам, которые вы описываете.
Я закончил делать это в коде. Хотя это код, это всего лишь одна строка кода и все еще довольно декларативная, поэтому я могу жить с ней. Однако я действительно надеюсь, что это будет решено в следующей версии WPF.
Вот пример строки кода из одного из моих проектов:
this.InputBindings.Add(new KeyBinding(
((MedicContext)this.DataContext).SynchronizeCommand,
new KeyGesture(Key.F9)));
SynchronizeCommand в этом случае является экземпляром RelayCommand, и (очевидно) F9 запускает его.
Вы можете подклассифицировать KeyBinding, добавить свойство зависимости CommandBinding
, которое устанавливает свойство Command, а затем добавить его в XAML, как и любое другое связывание с вводом.
public class RelayKeyBinding : KeyBinding
{
public static readonly DependencyProperty CommandBindingProperty =
DependencyProperty.Register("CommandBinding", typeof(ICommand),
typeof(RelayKeyBinding),
new FrameworkPropertyMetadata(OnCommandBindingChanged));
public ICommand CommandBinding
{
get { return (ICommand)GetValue(CommandBindingProperty); }
set { SetValue(CommandBindingProperty, value); }
}
private static void OnCommandBindingChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var keyBinding = (RelayKeyBinding)d;
keyBinding.Command = (ICommand)e.NewValue;
}
}
XAML:
<Window.InputBindings>
<RelayKeyBinding
Key="PageUp"
CommandBinding="{Binding SelectPreviousLayerCommand}" />
</Window.InputBindings>
Вы можете использовать класс CommandReference.
Очень элегантный код и работает как шарм.
Взгляните на: Как связать нажатие клавиши с делегатом Commommate в составном WPF?
Он работает так же с RelayCommands, но не обновляет CanExecutes, так как CommandReference не использует вызов CommandManager.RequerySuggested
Все, что вам нужно сделать для достижения автоматической переоценки CanExecute
, заключается в следующем изменении внутри класса CommandReference
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Я создаю привязку клавиш в моей модели представления, которая связывает команду и ключ таким образом
this.KeyBinding = new KeyBinding();
//set the properties
this.KeyBinding.Command = this.Command;
this.KeyBinding.Key = this.Key;
//modifier keys may or may not be set
this.KeyBinding.Modifiers = this.ModifierKeys;
тогда я создаю коллекцию элементов InputBinding в моем корне модели View Model и добавляю их в окна InputBindings в моем оконном коде за
foreach (var item in applicationViewModel.InputBindingCollection) {
this.InputBindings.Add(item);
}
его плохая форма, чтобы делать вещи в коде, который я знаю, но я не знаю, как сделать привязку еще, но я все еще работаю над этим.:) Единственное, что этот аргумент дает мне, - это список ключевых команд в меню, но это должно произойти.
Предполагая, что ваши RoutedCommands определены статически:
#region DeleteSelection
/// <summary>
/// The DeleteSelection command ....
/// </summary>
public static RoutedUICommand DeleteSelection
= new RoutedUICommand("Delete selection", "DeleteSelection", typeof(ChemCommands));
#endregion
Привязать к XAML таким образом:
<Canvas.InputBindings>
<KeyBinding Key="Delete" Command="{x:Static Controls:ChemCommands.DeleteSelection}" />
</Canvas.InputBindings>
Привет,
Тим Хотон