Command接口
数据绑定非常强大。数据绑定将View中可视元素的属性与ViewModel中的数据属性相关联,并允许通过用户界面直接操作数据项。
但并非一切都是财产。有时ViewModels会根据用户与可视元素的交互来公开必须从View调用的公共方法。如果没有MVVM,您可能会从Button的Clicked事件处理程序或TapGestureRecognizer的Tapped事件处理程序中调用此类方法。在考虑这些需求时,数据绑定和MVVM的整个概念可能开始显得无可救药地存在缺陷。如何删除页面类的代码隐藏文件
到InitializeComponent调用,如果它仍然必须从View到ViewModel进行方法调用?
不要那么快就放弃MVVM! Xamarin.Forms支持一种功能,允许数据绑定直接从Button和TapGestureRecognizer以及其他一些元素在ViewModel中进行方法调用。这是一个称为命令接口或命令接口的协议。
命令接口由八个类支持:
- Button
- MenuItem(在第19章“集合视图”中介绍),因此也是ToolbarItem
- SearchBar
- TextCell,因此也是ImageCell(也将在第19章中介绍)
- ListView(也将在第19章中介绍)
- TapGestureRecognizer
也可以在自己的自定义类中实现命令。
命令界面起初可能有点令人困惑。 让我们关注Button。
Button定义了两种方法,可以在单击元素时通知代码。 第一个是Clicked事件。 但您也可以使用按钮的命令界面作为Clicked事件的替代(或除此之外)。 该接口由Button定义的两个公共属性组成:
- 类型为System.Windows.Input.ICommand的命令。
- 类型为Object的CommandParameter
为了支持命令,ViewModel必须定义ICommand类型的公共属性,然后通过普通数据绑定将其连接到Button的Command属性。
与INotifyPropertyChanged一样,ICommand接口不是Xamarin.Forms的一部分。它在System.Windows.Input命名空间中定义,并在System.ObjectModel程序集中实现,该程序集是链接到Xamarin.Forms应用程序的.NET程序集之一。 ICommand是Xamarin.Forms支持的System.Windows.Input命名空间中唯一的类型。实际上,它是Xamarin.Forms支持的任何System.Windows命名空间中的唯一类型。
INotifyPropertyChanged和ICommand是否在.NET程序集中定义而不是Xamarin.Forms,这是巧合吗?不可以。这些界面通常用于ViewModels,一些开发人员可能已经为一个或多个基于XAML的环境开发了ViewModel。如果在标准.NET命名空间和程序集中定义INotifyPropertyChanged和ICommand而不是在Xamarin.Forms中,那么开发人员最容易将这些现有的ViewModel合并到Xamarin.Forms中。
ICommand接口定义了两个方法和一个事件:
public interface ICommand
{
void Execute(object arg);
bool CanExecute(object arg);
event EventHandler CanExecuteChanged;
}
为了实现命令,ViewModel定义了一个或多个ICommand类型的属性,这意味着该属性是实现这两个方法和事件的类型。然后,ViewModel中实现ICommand的属性可以绑定到Button的Command属性。单击Button时,Button会像往常一样触发其正常的Clicked事件,但它也会调用绑定到其Command属性的对象的Execute方法。 Execute方法的参数是设置为Button的CommandParameter属性的对象。
这是基本技术。但是,可能是ViewModel中的某些条件禁止在当前时间单击按钮。在这种情况下,应禁用Button。这是ICommand中CanExecute方法和CanExecuteChanged事件的目的。首次设置Command属性时,Button会调用CanExecute。如果CanExecute返回false,则Button会自行禁用,并且不会生成Execute调用。 Button还为CanExecuteChanged事件安装了一个处理程序。此后,每当ViewModel触发CanExecuteChanged事件时,该按钮再次调用CanExecute以确定是否应该启用该按钮。
支持命令接口的ViewModel定义ICommand类型的一个或多个属性,并在内部将此属性设置为实现ICommand接口的类。这节课是什么,它是如何运作的?
如果您在Microsoft的一个基于XAML的环境中实现命令协议,那么您将编写自己的类来实现ICommand,或者可能使用您在Web上找到的类,或者某些MVVM工具附带的类。有时这些类名为CommandDelegate或类似的东西。
您可以在Xamarin.Forms应用程序的ViewModels中使用相同的类。但是,为方便起见,Xamarin.Forms包含两个实现ICommand的类,您可以使用它们。这两个类简单地命名为Command和Command ,其中T是Execute和CanExecute的参数类型。
如果您确实在Microsoft环境和Xamarin.Forms之间共享ViewModel,则不能使用Xamarin.Forms定义的Command类。但是,您将使用类似于这些Command类的内容,因此以下讨论无论如何都将适用。
Command类包括ICommand接口的两个方法和事件,还定义了ChangeCanExecute方法。此方法导致Command对象触发CanExecuteChanged事件,并且该设施非常方便。
在ViewModel中,您可能会为ICommand类型的ViewModel中的每个公共属性创建一个Command或Command 类型的对象。 Command或Command 构造函数需要一个Action对象形式的回调方法,当Button调用ICommand接口的Execute方法时,该对象被调用。 CanExecute方法是可选的,但采用的形式
返回bool的Func对象。
在许多情况下,ICommand类型的属性是在ViewModel的构造函数中设置的,之后不会更改。因此,这些ICommand属性通常不需要触发PropertyChanged事件。