DependencyProperty 属性之事件

依赖属性提供一种全局内部属性存储来在运行时支持应用内的所有依赖属性,从而扩展基本的 Windows 运行时属性功能。这种方法可以替代为具有专用字段的属性(在属性定义类中为专用)提供支持的标准模式。你可以将此内部属性存储视为任何特定对象的一组属性标识符和值(只要该对象是 DependencyObject 即可)。属性存储中的每个属性均通过 DependencyProperty 实例(而不是通过名称)进行标识。但是,大多数情况下,属性系统会隐藏该实现详细信息:你可以使用简单名称频繁访问依赖属性

1
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback);

Register重载方法最多提供了三种回调:

类 型 说 明
ValidateValueCallback 验证回调
PropertyChangedCallback 值改变回调
CoerceValueCallback 强制转化回调

下面我们来研究一下这三种回调的优先级和作用:

首先写一个父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TestDe:DependencyObject     {
public int TestInt
{
get { return (int)GetValue(TestInt_Property); }
set { SetValue(TestInt_Property, value); }
}
public static readonly DependencyProperty TestInt_Property = DependencyProperty.Register
("TestInt", typeof(int), typeof(TestDe), new PropertyMetadata(100, PropertyChanged, Coerce) , Validate);
static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine(String.Format("PropertyChanged:{0} NewValue:{1} OldValue:{2}", e.Property.Name, e.NewValue, e.OldValue));
}
static object Coerce(DependencyObject dobj, object newValue)
{
Console.WriteLine(String.Format("Coerce - {0}", newValue));
return newValue;
}
static bool Validate(object obj)
{
Console.WriteLine(String.Format("Validate - {0}", obj));
return true;
}
}

然后实例化这个类:

1
2
3
4
5
static void Main(string[] args)
{
TestDe Anti = new TestDe();
Console.ReadLine();
}

我们会发现,验证回调事件被执行了两遍,这是因为 实例化TestDe这个类的时候(因为int初始值为0),被验证了一次了,然后我们的注册函数给初始值的100的时候又验证了一次。

继续探索,我们开始修改这个对象的属性:

1
2
3
4
5
6
static void Main(string[] args)
{
TestDe Anti = new TestDe();
Anti.TestInt = 300;
Console.ReadLine();
}

这次一共输出了5个条目,前两条前面已经说过了,我们开始解释后面。

▲Validate - 300 这个是我们实例化之后修改属性值触发的验证回调事件
▲Coerce - 300 这个是强制转化的回调触发事件,为什么要一定要触发这个事件呢?查询MSDN发现:

img
因为属性值在赋值的时候,可能是通过一些函数方法触发的,比如Parse之类的,他们的类型是一个string,所以依赖属性会触发这个强制转换。

▲PropertyChanged: TestInt NewValue : 300 OldaValue:100

这个就不用说了,核心部分,就是当属性值改变的时候会触发的回调方法。

那么这个触发链可以看成是

验证 —》 强制转换 —》属性值改变回调

下面我研究的就是属性值的改变,验证回调的触发和规则:、
首先我们更改一下验证回调:

我们发现会触发ArgumentException异常,提示300不是TestInt的有效值,因为我们在回调验证函数里面写了 如果大于 300 则 返回 false

接下来我们研究一下子类重写父类的这些回调会发生什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestChild:TestDe     {
static TestChild()
{
TestDe.TestInt_Property.OverrideMetadata(typeof(TestChild), new PropertyMetadata(99, PropertyChanged, Coerce));
}
static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine(String.Format("TestChild Class - PropertyChanged:{0} NewValue:{1} OldValue:{2}", e.Property.Name, e.NewValue, e.OldValue));
}
static object Coerce(DependencyObject dobj, object newValue)
{
Console.WriteLine(String.Format("TestChild Class - Coerce - {0}", newValue));
return newValue;
}
}

实例化:

我们会发现,父类,子类验证都会触发

我们更改子类的依赖属性值试试:

子类和父类的验证和属性改变回调都会依次被调用,但是强制转换只调用子类的。

评论