前一篇 简单的介绍了Fody/PropertyChanged的使用方法, 这一篇,我们详细介绍它的一些比较重要的特性和规则
1. Attributes通过在类或属性上标记这些特性,可以在编译代码时,注入特定的功能
ImplementPropertyChangedAttribute为类标记此特性,可以实现INotifyPropertyChanged接口
[ImplementPropertyChanged] public class Person { public string Name { get; set; } } AlsoNotifyForAttribute在实现通知时,也同时通知其它属性
public class Person : INotifyPropertyChanged { [AlsoNotifyFor("FullName")] public string GivenName { get; set; } [AlsoNotifyFor("FullName")] public string FamilyName { get; set; } public event PropertyChangedEventHandler PropertyChanged; public string FullName { get; set; } }在GivenName或FamilyName变化时,会同时也通知FullName的变化
DoNotNotifyAttribute顾名思义,就是在编译时,不在此属性中注入变化通知的代码
public class Person : INotifyPropertyChanged { public string GivenName { get; set; } [DoNotNotify] public string FamilyName { get; set; } public event PropertyChangedEventHandler PropertyChanged; } DependsOnAttribute设置一个属性,在它依赖的属性变化时,通知此属性发生变化
public class Person : INotifyPropertyChanged { public string GivenName { get; set; } public string FamilyName { get; set; } public event PropertyChangedEventHandler PropertyChanged; [DependsOn("GivenName","FamilyName")] public string FullName { get; set; } } DoNotSetChangedAttribute通过约定,在实现的类里,如果有一个属性是IsChanged
public bool IsChanged { get; set; }在其它类发生变化时,此类的值会自动被设置为True,
如果希望在某个属性变化时,,不响应此规则,可以将属性标记为DoNotSetChangedAttribute
public class Person: INotifyPropertyChanged { [DoNotSetChanged] public string FullName { get; set; } public bool IsChanged { get; set; } public event PropertyChangedEventHandler PropertyChanged; }在FullName变化里,不会将IsChanged设置为True
DoNotCheckEqualityAttribute默认情况下,所有注入的变化响应,都会检查是否相等,如果相等,则不会进行通知;但在某些时候,我们也许需要无论是否相等都进行通知,这个时候,可以在属性上标记DoNotCheckEqualityAttribute以跳过是否相等的检查
public class Person: INotifyPropertyChanged { [DoNotCheckEquality] public string FullName { get; set; } public bool IsChanged { get; set; } public event PropertyChangedEventHandler PropertyChanged; }这样,在给FullName赋值时,无论是否和之前的值相等,都会进行通知。
2. BeforeAfter有时候,我们需要在值发生变化时,访问变化之前和之后的值,比如做验证时,我们可以通过加入下面的方法实现:
public void OnPropertyChanged(string propertyName, object before, object after)
比如,我们写的代码:
public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string Name { get; set; } public void OnPropertyChanged(string propertyName, object before, object after) { //Perform property validation var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }在编译时,对应的代码为:
public class Person : INotifyPropertyChanged { private string name; public event PropertyChangedEventHandler PropertyChanged; public string Name { get { return name; } set { object before = Name; name = value; OnPropertyChanged("Name", before, Name); } } public void OnPropertyChanged(string propertyName, object before, object after) { //Perform property validation var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 3. EqualityChecking在设置属性的值之前,会进行是否相等的检查:
public string Property1 { get { return property1; } set { if (!String.Equals(property1, value)) { property1 = value; OnPropertyChanged("Property1"); } } }用于检查是否相等的方法依赖于属性的数据类型,按照下面的顺序或规则进行比较:
如果类型是Nullable,则使用 Nullable.Equals(T?,T?)方法比较
如果类型包含有静态的方法Equals,则使用静态的方法对比两个参数
如果类型有==方法,则使用==比较参数
使用Object.Equals(object,object)比较
4.实现IsChanged标志在上面我们已经简单的介绍了IsChanged属性,具体的实现代码如下:
书写的代码
public class Person : INotifyPropertyChanged { public string Name { get; set; } public event PropertyChangedEventHandler PropertyChanged; public bool IsChanged { get; set; } }编译对应的代码 (省略比较的代码)
public class Person : INotifyPropertyChanged { string name; bool isChanged; public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged(string propertyName) { var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public string Name { get { return name; } set { name = value; IsChanged = true; OnPropertyChanged("Name"); } } public bool IsChanged { get { return isChanged; } set { isChanged = value; OnPropertyChanged("IsChanged"); } } }这样,在Name设置新值后,IsChanged属性会被设置为True
当然,在代码逻辑中,在适当的时候需要手动将IsChanged设置为false
还有一些配置和规则,可以参见https://github.com/Fody/PropertyChanged/wiki