【问题标题】:RoutedUICommand vs. ICommand in ViewModel & using InputBindingViewModel 中的 RoutedUICommand 与 ICommand 以及使用 InputBinding
【发布时间】:2012-02-26 06:02:14
【问题描述】:

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

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

结果是在文件菜单项下标有“打开 Ctrl + O”的菜单项。对于手势,InputBindings 会将输入手势映射到命令,但您会失去对 InputGestureText 的支持。

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

【问题讨论】:

  • 我遇到过这个问题,但这并不重要。我想使用某种附加属性用法,将 ICommand 链接到手势。请让我知道您在此问题上的进展。

标签: wpf xaml data-binding icommand


【解决方案1】:

查看反射器中的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,没有一种简单的方法可以创建派生自RoutedCommandDelegateCommand,因为它的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);
    }

}

【讨论】:

    猜你喜欢
    • 2015-11-13
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-16
    相关资源
    最近更新 更多