我结合了Josh Smith的Using RoutedCommands with a ViewModel in WPF,vbfox的Using CommandBindings in MVVM和我自己的旋转来指定RoutedUICommand Text和KeyGesture,同时在XAML中声明了CommandBinding。
优点:
xmlns:vm="clr-namespace:VMCommanding.ViewModel"
...
<UserControl.CommandBindings>
<jas:CommandSinkBinding
Command="vm:CommunityViewModel.KillAllMembersCommand" />
</UserControl.CommandBindings>
我正在使用MVVM Light Toolkit's Locator类来间接获取ViewModel,所以我不想这样做。此外,由于这是在底层创建一个正常的CommandBinding,您不能使用Bindings来指定命令(CommandBinding不从DependencyObject继承)。 vbfox通过创建自己的CommandBindings类来解决这个问题。
<f:Mvvm.CommandBindings>
<f:MvvmCommandBindingCollection>
<f:MvvmCommandBinding
Command="f:MyRoutedCommands.SomeRoutedCommand"
Target="{Binding MyCommandInViewModel}"
CanExecuteChangedSuggestRequery="True" />
</f:MvvmCommandBindingCollection>
</f:Mvvm.CommandBindings>
所以你必须在某个地方(在你的View目录中?)创建一个RoutedUICommand,在你的ViewModel中创建一个单独的ICommand。
相反,我“只”必须在我的ViewModel中实现ToggleReadComand:
_commandSink.RegisterCommand(_toggleReadCommand,
p => CanToggleRead,
p => ToggleRead());
...
public static readonly RoutedUICommand _toggleReadCommand =
new RoutedUICommand();
public static RoutedUICommand ToggleReadCommand
{
get { return _toggleReadCommand; }
}
private bool CanToggleRead
{
get { return Files.CurrentItem != null; }
}
private void ToggleRead()
{
ToggleFileInfoFields(f => f.Read = !f.Read);
}
我这样使用它:
<cmd:Mvvm.CommandBindings>
<cmd:MvvmCommandBindingCollection>
<cmd:MvvmCommandBinding Command="{Binding ToggleReadCommand}"
Gesture="Toggle _Read|Ctrl+R" />
</cmd:MvvmCommandBindingCollection>
</cmd:Mvvm.CommandBindings>
...
<MenuItem Header="_View">
<MenuItem Command="{Binding ToggleReadCommand}" />
</MenuItem>
我获得了使用RoutedUICommands的所有优点:Command文本自动显示在我的MenuItem中以及快捷键(包括禁用支持),我的菜单项UI(或任何其他绑定到ToggleReadCommand的控件)在一个中指定在我的视图中通过XAML放置(没有更多单独的CommandBindings和InputBindings),但我仍然可以将我的命令代码放在它所属的ViewModels中。
现在这是我的问题。首先,我希望能够做到这一点(模拟如何声明正常的Window.CommandBindings):
<cmd:Mvvm.CommandBindings>
<cmd:MvvmCommandBinding Command="{Binding ToggleReadCommand}"
Gesture="Toggle _Read|Ctrl+R" />
</cmd:Mvvm.CommandBindings>
如何避免必须显式指定MvvmCommandBindingCollection?
My Gesture支持有效,但我在Visual Studio 2012 XAML编辑器的Gesture="Toggle _Read|Ctrl+R"
下面得到了“对象引用没有设置为对象的实例”错误指示?我将以下内容添加到vbfox的MvvmCodeBinding.cs:
public static readonly DependencyProperty GestureProperty =
DependencyProperty.Register(
"Gesture",
typeof(String),
typeof(MvvmCommandBinding),
new PropertyMetadata(null, OnGestureChanged));
static void OnGestureChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MvvmCommandBinding) d).OnGestureChanged((String) e.NewValue);
}
private string _gesture;
void OnGestureChanged(String newValue)
{
_gesture = newValue;
var command = _commandSinkBinding.Command as RoutedUICommand;
if (command == null)
return;
CreateGesture(command, newValue);
}
private static void CreateGesture(RoutedUICommand command, string gestureStr)
{
if (string.IsNullOrEmpty(gestureStr) || command == null)
return;
var fields = gestureStr.Split(new char[] {'|'}, 2);
if (fields.Length == 1)
command.Text = gestureStr;
else {
command.Text = fields[0];
var gesture = fields[1];
var kgc = new KeyGestureConverter();
var kg = kgc.ConvertFromString(gesture) as System.Windows.Input.KeyGesture;
command.InputGestures.Add(kg);
}
}
[Bindable(true)]
public String Gesture
{
get { return (String) GetValue(GestureProperty); }
set { SetValue(GestureProperty, value); }
}
(我还将vbfox的CommandBinding _commandBinding
更改为Smith的CommandSinkBinding _commandSinkBinding
,如果在Command之前创建了Gesture,则从OnCommandChanged()调用CreateGesture()。如何摆脱XAML编辑器错误指示?
最后,这有点像弗兰肯斯坦怪物。我确信有各种重复的功能。 vbfox明确表示他提出了他的代码以避免使用Smith的VMCommanding。另外,我开始使用MVVM Light Toolkit。我现在的东西只是一个“概念证明”,表明我的方法可行。
有人知道是否有更好的方法来完成已在某处实施的所有内容?我希望能够在XAML中声明我的RoutedUICommand(通过Binding)在一行中也设置Text和Gesture(不需要单独的CommandBinding&amp; InputBinding)。我希望实际的RoutedUICommands在我的ViewModel中实现。
如果没有,我可以通过仔细查看这三个软件包并进行一些重构来消除大量的kruft。