Mvvm中的ICommand是什么原因?

What is the reason for ICommand in Mvvm?

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

我不明白为什么我们需要在 mvvm 应用程序中使用这种方法。提供 public 方法并将视图中的操作直接绑定到此 public 方法是否足够?

为什么会存在ICommand?

Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method?

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

答案是将 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 中,您尽量避免 "code behind"(这是 MyView.cs 文件中的代码)以避免 View、ViewModel 和 Model 的紧密耦合。

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

Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method? Why ICommand exists?

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

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

  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

优雅

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

在 MVVM 中,我们避免代码隐藏模式。为此,我们需要将 DataContext 设置为其他 class(将充当中间件)说 MainWindowViewModel.cs .

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

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

<Button Command="{ViewModel AnyMethodName}"/>

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