在ViewModel中,RoutedUICommand和ICommand有何区别?如何使用InputBinding?

5

基本的ICommand界面实现,例如DelegateCommand和RelayCommand,缺少RoutedCommand类中包含的InputGestures属性。该属性支持绑定到KeyGesture,而RoutedUICommand中的Text属性则支持设置控件的标题。例如:

<MenuItem Header="File">
  <MenuItem Command="Open" />

结果是在“文件”菜单项下标记为“打开 Ctrl + O”的菜单项。对于手势,InputBindings 将手势映射到命令,但您会失去 InputGestureText 支持。
如何在 XAML 或视图模型中定义 KeyGestures 和 Text 的同时保持绑定视图模型的 ICommands 的简单性?例如,我想在上下文菜单和主菜单中公开一个命令,并显示与 RoutedUICommand 支持相同的标题和 InputGestureText,但命令的实现位于视图模型内而不是窗口的代码后面。

我曾遇到过这个问题,但它并不重要。我考虑使用某种附加属性用法将ICommand与手势链接起来。请告诉我您在解决此问题方面的进展情况。 - Jake Berger
1个回答

6

通过反射查看 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,没有一种简单的方法来创建从RoutedCommand派生的DelegateCommand,因为它的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
    }
}

但这并不妨碍对RoutedCommand上的非显式CanExecute/Execute方法进行调用,这可能是一个问题也可能不是。

或者,我们可以创建一个智能化的自定义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);
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接