目录
MVVM框架以自己的方式处理应用程序代码,并解释特定的代码片段。例如,如果一个属性的语法正确,那么它可以被认为是可绑定的。这些语法规则称为约定。约定允许你避免编写额外的代码,因为你知道框架将“理解”你期望从中得到什么,并自动生成所需的一切。本文收集了在构建MVVM应用程序时,所需要注意的所有MVVM框架约定。
- 可绑定属性注解(Bindable Properties)
- 属性依赖(Property Dependencies)
- 命令(Commands)
- 服务(Services)
可绑定属性注解
所有get/set的public virtual 属性都被视为可绑定的。
public virtual string Test { get; set; }
若要禁止为此类属性生成可绑定属性,请使用 [Bindable] 属性注解,如下所示:
[Bindable(false)]
public virtual string Test { get; set; }
带有"Field"结尾的属性会被框架忽略。您可以显式地使用 [BindableProperty] 属性注解,来标记这些属性,以使它们仍然能够用于数据绑定。
using DevExpress.Mvvm.DataAnnotations;
//. . .
string test;
[BindableProperty]
public virtual string Test
{
get { return test; }
set { test = value; }
}
属性依赖
属性可以在应用程序运行时更改其值。要跟踪这些更改并响应它们,请声明属性依赖关系。属性依赖项是在其相关属性更改或即将更改时自动执行的方法。要实现此行为,必须在更改时调用 On<Related_Property_Name>的方法,或者是在更改后调用On<Related_Property_Name>的方法。
public virtual string Test { get; set; }
protected void OnTestChanged() {
//do something
}
On...Changed和On..Changing 方法也可以有一个参数。在这种情况下,参数将分别接收旧的或新的属性值。
public virtual string Test { get; set; }
protected void OnTestChanging(string newValue) {
//do something
}
protected void OnTestChanged(string oldValue) {
//do something
}
[BindableProperty]属性注解还允许使用具有不同名称的方法。
[BindableProperty(OnPropertyChangingMethodName = "BeforeChange", OnPropertyChangedMethodName = "AfterChange")]
public virtual string Test { get; set; }
protected void BeforeChange() {
//. . .
}
protected void AfterChange() {
//. . .
}
命令
所有在POCO ViewModel 中声明的,且参数为零或只有一个的public void的方法都被视为命令。
public void DoSomething(object p) {
MessageBox.Show(string.Format("The parameter passed to command is {0}.", p));
}
名称以..Command结尾的方法会引发异常。你可以强制框架将这些方法视为有效的命令,通过使用 [Command] 属性注解标记方法,并设置Name参数合适的名称。
using DevExpress.Mvvm.DataAnnotations;
[Command(Name="DoSomething")]
public void DoSomethingCommand(object p) {
//do something
}
对于每个命令方法,框架都会生成一个相应的后备属性。默认情况下,此属性以相关方法加上“Command”后缀命名。您可以使用[Command] 属性注解的Name参数为这个自动生成的后备属性保留另一个名称。
[Command(Name = "MyMvvmCommand")]
public void DoSomething(object p) {
//do something
}
命令可以附带一个CanExecute子句——是一个返回值为boolean类型的方法,只有在返回true时才允许执行相关命令。这些方法必须被命名为Can<Related_Command_Name>。
//只有p等于4 的时候,这个命令才会被执行,
public void DoSomething(int p) {
MessageBox.Show(string.Format("The parameter passed to command is {0}.", p));
}
public bool CanDoSomething(int p) {
return (2 + 2) == p;
}
作为其他名称的CanExecute方法仍然可以通过使用 [Command] 属性注解的CanExecuteMethodName参数绑定到命令。
[Command(CanExecuteMethodName = "DoSomethingCriteria")]
public void DoSomething(int p) {
MessageBox.Show(string.Format("The parameter passed to command is {0}.", p));
}
public bool DoSomethingCriteria(int p) {
return (2 + 2) == p;
}
当命令刚刚绑定到它的目标(以获取目标的初始状态)时,首先检查CanExecute子句。稍后,每当CanExecuteChanged事件通知命令的目标有关命令状态更改时,将重新计算此标准。此事件在底层的Command-object级别声明。要从ViewModel级别发送这样的通知,调用RaiseCanExecuteChanged扩展方法,如下所示。
//一个可绑定的属性
public virtual bool IsModified { get; protected set; }
//一个命令
public void Save() {
//. . .
}
//一个可执行条件
public bool CanSave() {
return IsModified;
}
//the OnChanged method calls the RaiseCanExecuteChanged method for the "Save" command
//this forces the command to update its CanExecute condition
public void OnIsModifiedChanged() {
this.RaiseCanExecuteChanged(x=>x.Save());
}
服务
要解析服务,框架将重写接口类型的虚拟属性。这些属性的名称必须以…Service结尾。
public virtual IMyNotificationService MyService {
get { throw new NotImplementedException(); }
}
public virtual IMyNotificationService AnotherService {
get { throw new NotImplementedException(); }
}
您还可以使用 [ServiceProperty] 属性注解显式地用其他名称标记服务属性。
using DevExpress.Mvvm.DataAnnotations;
//. . .
[ServiceProperty]
public virtual IMyNotificationService MyProvider {
get { throw new NotImplementedException(); }
}
当框架重写一个服务属性时,它会生成相应的GetService<>扩展方法调用。[ServiceProperty]属性注解,允许你为这个方法指定额外的参数Key
[ServiceProperty(Key="Service1")]
public virtual IMyNotificationService Service {
get { throw new NotImplementedException(); }
}
[ServiceProperty(Key = "Service2")]
public virtual IMyNotificationService AnotherService {
get { throw new NotImplementedException(); }
}