基本的ICommand接口(interface)实现(例如DelegateCommand和RelayCommand)缺少RoutedCommand类中包含的InputGestures属性。此属性支持绑定(bind)到KeyGesture,并且RoutedUICommand中的Text属性支持设置控件的 header 。例如:
<MenuItem Header="File">
<MenuItem Command="Open" />
结果是在文件菜单项下标记为“打开Ctrl + O”的菜单项。对于手势,InputBindings会将输入内容映射到命令,但是您将失去对InputGestureText的支持。
在为XAML或 View 模型中的命令定义KeyGestures和Text时,如何保持绑定(bind)到 View 模型的ICommand的简单性?例如,我希望在上下文菜单和主菜单中显示的命令显示与RoutedUICommand支持的相同的Header&InputGestureText,但是该命令的实现位于 View 模型内部,而不位于Window后面的代码内部。
最佳答案
查看反射器中的MenuItem
,我们可以看到MenuItem如何获取Header
/InputGesture
值,即:
private static object CoerceInputGestureText(DependencyObject d, object value)
{
RoutedCommand command;
MenuItem item = (MenuItem) d;
if ((string.IsNullOrEmpty((string) value) &&
!item.HasNonDefaultValue(InputGestureTextProperty)) &&
((command = item.Command as RoutedCommand) != null))
{
InputGestureCollection inputGestures = command.InputGestures;
// Get appropriate gesture....
}
return value;
}
有类似的代码可基于当前命令强制Header属性,但在这种情况下,它将查找
RoutedUICommand
。这告诉我们,命令必须是RoutedCommand
/RoutedUICommand
的实例,才能利用MenuItem
的此功能。在反射器中查看
RoutedCommand
,没有一种简单的方法来创建从DelegateCommand
派生的RoutedCommand
,因为CanExecute
/Execute
方法不是虚拟的。我们可以编写类似以下内容的代码:
public class DelegateCommand : RoutedCommand, ICommand
{
bool ICommand.CanExecute(object parameter) {
// Insert delegate can execute logic
}
void ICommand.Execute(object parameter) {
// Insert delegate execute logic
}
}
但这不会阻止调用
CanExecute
上的非显式Execute
/RoutedCommand
方法。这可能是问题,也可能不是问题。另外,我们可以创建一个自定义的
MenuItem
,它很聪明,可以查找我们的DelegateCommand(或其他地方)并使用它的文本/手势。public class MyMenuItem : MenuItem {
static MyMenuItem() {
InputGestureTextProperty.OverrideMetadata(typeof(MyMenuItem),
new FrameworkPropertyMetadata(string.Empty, null, CoerceInputGestureText));
}
private static object CoerceInputGestureText(DependencyObject d, object value) {
MenuItem item = (MenuItem)d;
var command = item as DelegateCommand;
if ((string.IsNullOrEmpty((string)value) &&
DependencyPropertyHelper.GetValueSource(item, InputGestureTextProperty).BaseValueSource == BaseValueSource.Default &&
command != null) {
InputGestureCollection inputGestures = command.InputGestures;
// Get appropriate gesture....
}
// Call MenuItem Coerce
var coerce = InputGestureTextProperty.GetMetadata(typeof(MenuItem)).CoerceValueCallback;
return coerce(d, value);
}
}