简体   繁体   English

Mvvm中ICommand的原因是什么?

[英]What is the reason for ICommand in Mvvm?

In application using a mvvm-approach it's pretty common that the ViewModel provides one or more Command -properties.在使用 mvvm 方法的应用程序中,ViewModel 提供一个或多个Command属性是很常见的。 These properties often have the type ICommand or DelegateCommand or something like that.这些属性通常具有ICommandDelegateCommand类型或类似的类型。

I don't understand why we need such an approach in an mvvm application.我不明白为什么我们需要在 mvvm 应用程序中使用这种方法。 Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method?提供公共方法并将视图中的操作直接绑定到此公共方法还不够吗?

Why does ICommand exist?为什么 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?为什么 ICommand 存在?

  1. you can't bind to a method in xaml.您不能绑定到 xaml 中的方法。 You need an object.你需要一个对象。 Therefore you need to wrap the method to an object.因此,您需要将该方法包装到一个对象中。

  2. it is a common pattern in UI, that some actions are not available all the time.这是 UI 中的一种常见模式,即某些操作并非始终可用。 In Login form the Login action become available only when you enter username.在登录表单中,登录操作仅在您输入用户名时才可用。 In MS Word, the Copy or Cut actions becomes available only when you select something, otherwise the buttons are disabled and keyboard shortcuts inactive在 MS Word 中,复制或剪切操作仅在您选择某些内容时才可用,否则按钮将被禁用且键盘快捷键处于非活动状态

  3. it is a common pattern, that command can be invoked with different parameters.这是一种常见的模式,可以使用不同的参数调用该命令。

Plain eventhandlers does not meet those requirements, But ICommand servers exactly those purposes:普通的事件处理程序不满足这些要求,但ICommand正是为了这些目的:

public interface ICommand
{
    void Execute(object parameter);
    bool CanExecute(object parameter);
    event EventHandler CanExecuteChanged;
}
  1. It wraps method to an object它将方法包装到一个对象
  2. It says whether to command is available or no, so the UI component (typically a button or menuitem) can reflect it它表示命令是否可用,因此 UI 组件(通常是按钮或菜单项)可以反映它
  3. Additionally, it notifies the UI components that the availability of the command has changed, so the UI can reflect it.此外,它会通知 UI 组件命令的可用性已更改,因此 UI 可以反映它。

Now, let's consider Copy&Paste scenario.现在,让我们考虑复制和粘贴场景。 Using ICommand the markup can look like this:使用 ICommand 标记可以如下所示:

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

How would it look like without ICommand ?如果没有ICommand怎样? To make it easier, lets consider, that XAML would allow to bind to methods:为了更容易,让我们考虑一下,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);
        }
    }
}

as you can see, not only it is more verbose, but it's also violation of DRY principle.如您所见,它不仅更加冗长,而且还违反了 DRY 原则。 You need to specify both Paste and CanPaste binding every time you want to use the command.每次要使用该命令时,都需要指定PasteCanPaste绑定。 What if you started without CanPaste and later you wanted to add it.如果您开始时没有使用 CanPaste,后来又想添加它,该怎么办? Then you would have to add the CanPaste binding every occurrence of the Paste call.然后您必须在每次出现Paste调用时添加 CanPaste 绑定。 I guarantee you, that you would forget it somewhere.我向你保证,你会在某个地方忘记它。

Now, if you did this in WPF:现在,如果您在 WPF 中执行此操作:

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

or eventually:或最终:

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

Both approaches are correct, they follow MVVM priciples and works without ICommand, but as you can see, neither is as elegant as ICommand两种方法都是正确的,它们遵循 MVVM 原则并且在没有 ICommand 的情况下工作,但是正如您所看到的,它们都没有ICommand优雅

Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method?提供公共方法并将视图中的操作直接绑定到此公共方法还不够吗?

How would you for example call a public method when a Button in the view is clicked?例如,当单击视图中的Button时,您将如何调用公共方法?

The answer is that you bind the Command property of the Button to an ICommand property of the view model that calls the method for you.答案是您将ButtonCommand属性绑定到为您调用该方法的视图模型的ICommand属性。 That's the main reason why any actions that view model defines are exposed using commands.这是视图模型定义的任何操作都使用命令公开的主要原因。

A command is nothing but an object that implements the System.Windows.Input.ICommand interface and encapsulates the code for the action to be performed.命令只不过是一个对象,它实现了System.Windows.Input.ICommand接口并封装了要执行的操作的代码。

Please refer to the following links for more information about the concept.有关该概念的更多信息,请参阅以下链接。

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

In MVVM you try to avoid "code behind" (this is code in the MyView.cs file) to avoid a tight coupling of View, ViewModel and Model.在 MVVM 中,您尝试避免“代码隐藏”(这是 MyView.cs 文件中的代码)以避免 View、ViewModel 和 Model 的紧密耦合。

In MFC you just registered an event handler (which is still possible in WPF), but in MVVM there is the possibility of just binding a ICommand which will be executed instead of triggering the event.在 MFC 中,您刚刚注册了一个事件处理程序(这在 WPF 中仍然是可能的),但在 MVVM 中,有可能只绑定一个 ICommand,该 ICommand 将被执行而不是触发事件。

Short: ex.简短:例如。 Buttons Buttons works by creating event (Click="XEvent") that consist of method and then we tell application what to do next ie call other methods obviously that works with Code behind.按钮 按钮的工作原理是创建由方法组成的事件(Click="XEvent"),然后我们告诉应用程序接下来要做什么,即调用其他明显与代码一起工作的方法。 (Event => method is generated at MainWindow.xaml.cs .) (事件 => 方法在MainWindow.xaml.cs生成。)

In MVVM we avoid code behind pattern.在 MVVM 中,我们避免了模式背后的代码。 to achieve that we need to set the DataContext to other class (will act as middleware) say MainWindowViewModel.cs .为了实现这一点,我们需要将 DataContext 设置为其他类(将充当中间件),比如MainWindowViewModel.cs

By implementing ICommand interface and implementing methods to handle the command we avoid code behind maintain MVVM pattern.通过实现 ICommand 接口和实现处理命令的方法,我们避免了维护 MVVM 模式的代码。

Well there can be alternative to ICommand interface like to bind method in ViewModel to command in XAML (Wont prefer though) here那么可以有 ICommand 接口的替代方案,例如将 ViewModel 中的方法绑定到 XAML 中的命令(尽管不喜欢)here

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

PLUS ICommand interface will provide you CanExecute method which can be used to enable/Disable controllers simple delegate wont give u that functionality Hope this helps :) PLUS ICommand 接口将为您提供 CanExecute 方法,该方法可用于启用/禁用控制器简单委托不会为您提供该功能希望这会有所帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM