WPF开发进阶 - Fody/PropertyChanged(二)
前一篇 简单的介绍了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