#51 依赖属性的实现
WPF客户端使用依赖属性的方式如同一般的CLR属性,但在类的定义中实现方式有差异。依赖属性增加了对数据绑定,属性集成和变更通知等等复杂的机制。 Class通过继承Denpendency Object来支持对Denpendency Properties的读写。
Class声明类型为DependencyProperty的新属性的静态变量。使用DependencyProperty.Register方法来创建静态实例。这个实例并不存储任何属性,只存储该属性的元数据。
public static readonly DependencyProperty AgeProperty = DependencyProperty.Register("Age", typeof(int), typeof(Person));
在继承了Denpendency Object的类中通过属性的 GetValue and SetValue方法来读写该依赖属性。
public int Age { get { return (int)GetValue(AgeProperty); } set { SetValue(AgeProperty, value); } }
#52 依赖属性的实现
标准的CLR属性值是存储在定义它的类的实例中。即使你从更改过它的默认值,它仍会占据这个对象相应的内存。
而依赖属性当且仅当它赋予非默认值时才会被存储。如若你未设置该属性的默认值,客户端读取时则会返回该属性的默认值。
依赖属性的值被拥有它并且继承了DependencyObject的类存储在一个数组中。这个储存了依赖属性值得数组,以及GetValue和SetValue方法来读写依赖属性值的特点,是继承自DependencyObject类的特点。这个内部的数组会存储每个设置过了非默认值的依赖属性值。
#53 注册依赖属性
实现依赖属性,首先要创建一个DependencyProperty的静态实例,因为其作用是为了读写元属性值,而并不是存储其实际属性值。所以其为静态的。
步骤:1. 声明一个静态的DependencyProperty实例:
public static readonly DependencyProperty AgeProperty;
2. 在静态的构造函数里,使用DependencyProperty.Register
static Person() { PropertyMetadata ageMetadata = new PropertyMetadata( 18, // Default value new PropertyChangedCallback(OnAgeChanged), new CoerceValueCallback(OnAgeCoerceValue)); // Register the property AgeProperty = DependencyProperty.Register( "Age", // Property's name typeof(int), // Property's type typeof(Person), // Defining class' type ageMetadata, // Defines default value & callbacks (optional) new ValidateValueCallback(OnAgeValidateValue)); // validation (optional) }
注册的前三个参数是必须的。
你也可以指定:1. 属性默认值。2.属性值改变时的通知方法。3. 验证值合法性。
#54 不要在DependencyProperty的Getter/Setter方法里加入逻辑
要实现依赖属性,需要使用 DependencyObject.GetValue and DependencyObject.SetValue 方法来实现Getter/Setter. 这样就实现了依赖属性正常的CLR属性功能。
public int Age { get { return (int)GetValue(AgeProperty); } set { SetValue(AgeProperty, value); } }
你不应该在get和set中使用除了getvalue和setvalue以外的方法。因为在xaml中获取或者赋值的时候,wpf会直接调用getvalue和setvalue方法,绕过你在里面写的逻辑。你应该在获取或者设置的回调方法里来写入你的逻辑。
#55 在Xaml或者cs代码里读取/写入依赖属性值
在Xaml或者cs代码里都可以读取/写入依赖属性的值。
例如在Person类里我们实现了三个依赖属性, FirstName, LastName, Age. 在Xaml中可以这样使用:
<m:Person x:Key="guy" FirstName="Samuel" LastName="Clemens" Age="75"/>
代码中可以这样:
Person author = (Person)this.Resources["guy"]; string info = string.Format("{0} {1}, aged {2}", author.FirstName, author.LastName, author.Age);
#56 清除依赖属性
在Xaml或者cs代码里都可以通过写入依赖属性的值来对默认或者继承的依赖属性值进行覆盖。
也可以使用DependencyObject.ClearValue方法来清除该依赖属性值。这将会取消掉任何设置在该依赖属性的值,恢复其为默认值。
Person p = new Person("Samuel", "Clemens"); Console.WriteLine(p.Age); // 18 (the default) // Setting a property value p.Age = 70; Console.WriteLine(p.Age); // 70 // Clear a property value p.ClearValue(Person.AgeProperty); Console.WriteLine(p.Age); // 18 again