【问题标题】:What is the reason for ICommand in Mvvm?Mvvm中ICommand的原因是什么?
【发布时间】:2017-02-08 12:39:20
【问题描述】:

在使用 mvvm-approach 的应用程序中,ViewModel 提供一个或多个 Command-属性是很常见的。这些属性通常具有 ICommandDelegateCommand 或类似的类型。

我不明白为什么我们需要在 mvvm 应用程序中使用这种方法。提供公共方法并将视图中的操作直接绑定到这个公共方法还不够吗?

ICommand 为什么存在?

【问题讨论】:

  • "将视图中的操作直接绑定到此公共方法" - 这就是ICommand 所做的事情,以及在命令 可以时告诉视图> 被处决。看看DelegateCommand,它很简单。
  • 一些 MVVM 框架,如 Caliburn.Micro 使用命名约定来绑定方法来查看元素没有 ICommand。
  • 可以通过附加行为(纯 MVVM)相对轻松地添加自己的功能:您可以订阅某些 View 事件(您可以在 View 代码隐藏中完成,但是这将是肮脏的 MVVM)调用 ViewModel 的某些方法(直接,通过接口或使用反射)。 ICommand 是 WPF 需要的最低要求,即它解决了菜单项/按钮被禁用时的问题,例如对于Copy/Paste 场景。而已。其实ButtonBase.Command 可以是一个简单的Click 事件处理器,你可以马上调用那里的ViewModel 方法。

标签: c# wpf mvvm icommand


【解决方案1】:

提供公共方法并绑定操作还不够吗 从视图直接到这个公共方法?为什么 ICommand 存在?

  1. 您不能绑定到 xaml 中的方法。你需要一个对象。因此,您需要将方法包装到一个对象中。

  2. 这是 UI 中的一种常见模式,即某些操作并非始终可用。在登录表单中,登录操作仅在您输入用户名时才可用。在 MS Word 中,复制或剪切操作仅在您选择某些内容时才可用,否则按钮将被禁用且键盘快捷键无效

  3. 这是一种常见的模式,可以使用不同的参数调用该命令。

普通事件处理程序不满足这些要求,但ICommand 服务器正是这些目的:

public interface ICommand
{
    void Execute(object parameter);
    bool CanExecute(object parameter);
    event EventHandler CanExecuteChanged;
}
  1. 它将方法包装到一个对象中
  2. 它表示命令是否可用,因此 UI 组件(通常是按钮或菜单项)可以反映它
  3. 此外,它会通知 UI 组件该命令的可用性已更改,以便 UI 可以反映它。

现在,让我们考虑复制和粘贴场景。使用 ICommand 标记可以如下所示:

<Button Content="Paste" Command="{Binding PasteCommand}" />
<MenuItem Header="Paste" Command="{Binding PasteCommand}" />
public ICommand PasteCommand {get;} = new DelegateCommand(Paste, () => Clipboard != null);

如果没有ICommand,它会是什么样子?为了更容易,让我们考虑一下,XAML 将允许绑定到方法:

<Button Content="Paste" Click="{Binding Paste}" IsEnabled="{Binding CanPaste}" />
<MenuItem Header="Paste" Click="{Binding Paste}" IsEnabled="{Binding CanPaste}"/>

public void Paste() {....}

private bool _canPaste;
public bool CanPaste
{
    get { return _canPaste }
    set 
    { 
        if (_canPaste != value)
        {
            _canPaste = value;
            OnNotifyPropertyChanged(nameof(CanPaste);
        }
    }
}

如您所见,它不仅更加冗长,而且还违反了 DRY 原则。每次要使用该命令时,都需要同时指定 PasteCanPaste 绑定。如果您一开始没有 CanPaste,后来又想添加它怎么办。然后,您必须在每次出现 Paste 调用时添加 CanPaste 绑定。我向你保证,你会在某个地方忘记它。

现在,如果您在 WPF 中执行此操作:

<Button Content="Paste" Click="Call_ViewModel_Paste" />
//in codebehind:
void Call_ViewModel_Paste(oobject sender, RoutedEventArgs e)
{
    ViewModel.Paste();
}

或最终:

<Button Content="Paste">
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="Click">
             <ei:CallMethodAction MethodName="Paste" TargetObject="{Binding}"/>
         </i:EventTrigger>
     </i:Interaction.Triggers>
</Button>

这两种方法都是正确的,它们遵循 MVVM 原则,并且在没有 ICommand 的情况下也可以工作,但正如您所见,它们都不像 ICommand 那样优雅

【讨论】:

    【解决方案2】:

    提供公共方法并将视图中的操作直接绑定到这个公共方法还不够吗?

    例如,当单击视图中的Button 时,您将如何调用公共方法?

    答案是您将ButtonCommand 属性绑定到为您调用该方法的视图模型的ICommand 属性。这就是为什么视图模型定义的任何操作都使用命令公开的主要原因。

    命令只不过是一个对象,它实现了System.Windows.Input.ICommand 接口并封装了要执行的操作的代码。

    有关该概念的更多信息,请参阅以下链接。

    https://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/ https://msdn.microsoft.com/en-us/magazine/dn237302.aspx

    【讨论】:

    • »命令只不过是一个对象...封装了要执行的操作的代码。« – 但这正是它不是的,是吗?命令只是一种标记,实际动作来自命令绑定
    • 您没有在 MVVM 中使用 System.Windows.Input.CommandBinding。您绑定到返回 ICommand 对象的视图模型的属性,然后当您单击视图中的按钮时调用此 ICommand 对象的 Execute 方法。
    • 这个答案如何why WPF 命令以它们的方式工作?看起来 OP 在问为什么我们不能写 {Binding MethodName} 而不是 {Binding CommandObject}
    【解决方案3】:

    在 MVVM 中,您尝试避免“代码隐藏”(这是 MyView.cs 文件中的代码)以避免 View、ViewModel 和 Model 的紧密耦合。

    在 MFC 中,您刚刚注册了一个事件处理程序(在 WPF 中仍然可以),但在 MVVM 中,有可能只绑定一个将被执行而不是触发事件的 ICommand。

    【讨论】:

    • 您可以将 View 绑定到 ViewModel 中的方法。实际上,您可以在 xaml 中使用 CallMethodAction 来实现。所以这并不是我们需要 ICommand 的真正答案
    • 但是一个命令更加灵活,因为它是一个可以自定义的整个类。例如。使用其他属性等。
    【解决方案4】:

    短: 前任。纽扣 按钮通过创建由方法组成的事件 (Click="XEvent") 来工作,然后我们告诉应用程序接下来要做什么,即调用其他显然与 Code behind 一起工作的方法。 (事件 => 方法在 MainWindow.xaml.cs 处生成。)

    在 MVVM 中,我们避免使用代码隐藏模式。要实现这一点,我们需要将 DataContext 设置为其他类(将充当中间件),例如 MainWindowViewModel.cs

    通过实现 ICommand 接口和实现处理命令的方法,我们避免了维护 MVVM 模式的代码。

    嗯,可以替代 ICommand 接口,例如将 ViewModel 中的方法绑定到 XAML 中的命令(虽然不喜欢) 这里

    &lt;Button Command="{ViewModel AnyMethodName}"/&gt;

    加 ICommand 接口将为您提供 CanExecute 方法,该方法可用于启用/禁用控制器简单的委托不会为您提供该功能 希望这会有所帮助:)

    【讨论】:

      猜你喜欢
      • 2017-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-28
      • 2016-09-01
      • 2011-12-04
      • 2011-08-29
      • 1970-01-01
      相关资源
      最近更新 更多