ViewModel中的RoutedUICommand与ICommand以及使用InputBinding

Geo*_*kos 5 data-binding wpf xaml icommand

基本的ICommand接口实现(例如DelegateCommand和RelayCommand)缺少RoutedCommand类中包含的InputGestures属性。此属性支持绑定到KeyGesture,并且RoutedUICommand中的Text属性支持设置控件的标头。例如:

<MenuItem Header="File">
  <MenuItem Command="Open" />
Run Code Online (Sandbox Code Playgroud)

结果是在File(文件)菜单项下标记为“ Open Ctrl + O”的菜单项。对于手势,InputBindings会将输入来宾映射到命令,但是您松开了InputGestureText支持。

在为XAML或视图模型中的命令定义KeyGestures和Text时,如何保持绑定到视图模型的ICommand的简单性?例如,我希望在上下文菜单和主菜单中显示的命令显示与RoutedUICommand支持的相同的Header和InputGestureText,但是该命令的实现位于视图模型内部,而不位于Window后面的代码内部。

Cod*_*ked 6

看着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;
}
Run Code Online (Sandbox Code Playgroud)

有类似的代码可基于当前命令强制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
    }
}
Run Code Online (Sandbox Code Playgroud)

但这不会阻止非显式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);
    }

}
Run Code Online (Sandbox Code Playgroud)