依赖属性之“风云再起”三
发布时间:2020-05-23 07:08:54 所属栏目:程序设计 来源:互联网
导读:八. DependencyObject测试代码 在写DependencyObject测试代码之前,我们先看一下它到底有哪些成员和方法,如下图: 通过上面的这幅图,我们知道它的主要功能包括:各种依赖属性的GetValue、SetValue操作(核心功能)和ClearValue、 CoerceValue、GetLocalValu
八. DependencyObject测试代码在写DependencyObject测试代码之前,我们先看一下它到底有哪些成员和方法,如下图:
1: class X {
2: //注册一个附加依赖属性A 3: public static readonly DependencyProperty AProperty = DependencyProperty.RegisterAttached("A",typeof(int),255);">typeof(X));
4: //获取附加属性A的值 5: void SetA(DependencyObject obj,255);">int value) 6: {
7: obj.SetValue(AProperty,255);">value); 8: } 9: //设置附加属性A的值 10: int GetA(DependencyObject obj) 11: {
12: return (int)obj.GetValue(AProperty); 13: } 14: //注册一个附加依赖属性B 15: readonly DependencyProperty BProperty = DependencyProperty.RegisterAttached("B",255);">string),255);">typeof(X));
16: //设置附加属性B的值 17: void SetB(DependencyObject obj,255);">string value) 18: {
19: obj.SetValue(BProperty,255);">value); 20: } 21: //获取附加属性B的值 22: string GetB(DependencyObject obj) 23: {
24: string)obj.GetValue(BProperty); 25: } 26: 27: } 28: 29: class Y : DependencyObject {
30: }第三个类则是为了直接测试注册一个依赖属性,这个类首先继承自DependencyObject原型类。 class Z : DependencyObject 2: {
3: readonly DependencyProperty SimpleDPProperty = 4: DependencyProperty.Register("SimpleDP",255);">double),255);">typeof(Z),
5: new PropertyMetadata((double)0.0, 6: new PropertyChangedCallback(OnValueChanged), 7: new CoerceValueCallback(CoerceValue)), 8: new ValidateValueCallback(IsValidValue)); 9: 10: double SimpleDP 11: {
12: get { double)GetValue(SimpleDPProperty); }
13: set { SetValue(SimpleDPProperty,255);">value); }
14: } 15: 16: private void OnValueChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) 17: {
18: Console.WriteLine("当值改变时,我们可以做的一些操作,具体可以在这里定义: {0}",e.NewValue);
19: } 20: 21: object CoerceValue(DependencyObject d,255);">object value) 22: {
23: Console.WriteLine("对值进行限定,强制值: {0}",255);">value);
24: return value; 25: } 27: bool IsValidValue(value) 28: {
29: Console.WriteLine("验证值是否通过,如果返回True表示验证通过,否则会以异常的形式暴露: {0}",255);">value);
30: true; 31: } 32: 33: }首先我们先写测试GetValue和SetValue操作的测试代码,然后不能通过,最后完善DependencyObject类的GetValue和SetValue方法直到测试用例通过。 1: [Test] 2: [Category ("NotWorking")]
3: void TestAttachedProperty() 4: {
5: Y y1 = new Y(); 6: X.SetA(y1,2); 7: Assert.AreEqual(2,X.GetA(y1)); 8: }由于这里是y1和y2两个对象,所以他们的GetValue和SetValue也是设置和取得各自的值。 2: [Category (void Test2AttachedProperties() 4: {
5: Y y1 = 6: Y y2 = new Y(); 7: X.SetA(y1,2); 8: X.SetA(y2,3); 9: Assert.AreEqual(2,X.GetA(y1)); 10: Assert.AreEqual(3,X.GetA(y2)); 11: }通过前面的图,大家可以看到DependencyObject提供了一个取得本地值枚举器的GetLocalValueEnumerator方法,它实现一个IEnumerator来方便访问LocalValue,这里我们要实现它,所以先写测试代码。 void TestEnumerationOfAttachedProperties() 5: int count = 0; 6: Y y = 7: X.SetA(y,96);"> 8: X.SetB(y,128);">"Hi"); 10: //根据DependencyObject得到所有本地值 11: LocalValueEnumerator e = y.GetLocalValueEnumerator(); while (e.MoveNext()) {
13: count++; 14: if (e.Current.Property == X.AProperty) 15: Assert.AreEqual(e.Current.Value,2); 16: else if (e.Current.Property == X.BProperty) 17: Assert.AreEqual(e.Current.Value,128);">"Hi"); 18: else 19: Assert.Fail("Wrong sort of property" + e.Current.Property);
20: } 21: //count为2 22: Assert.AreEqual(2,count); 23: }还有几个功能,既然Mono也没做研究,我们也就不费那个力气了,接下来我们就看看刚才实现的DependencyObject代码吧! 九. DependencyObject实现代码通过前面的测试用例,DependencyObject类的基本功能已经完成,不过我们要注意几个要点:1,依赖属性其实终究要DependencyObject和DependencyProperty成对才能算得上真正的DependencyProperty 2,不管是Register、RegisterAttached、RegisterAttachedReadOnly还是 RegisterReadOnly操作,我们都要通过DependencyObject来操作DependencyProperty的值,也就是通过 DependencyObject这个外部接口来操作,DependencyProperty只负责注册和内部处理,不负责外部接口。 3,在DependencyObject中提供了几个操作LocalValue的接口的接口,其中包括ReadLocalValue、GetLocalValueEnumerator、CoerceValue和ClearValue等。 4,在注册注册依赖属性时,实质是关联DependencyObject的propertyDeclarations,它是一个 Dictionary<Type,Dictionary<string,DependencyProperty>>类型,但是在 register代码中并没有完全关联起来,我也比较纳闷,所以这点还希望和大家一起探讨,微软的BCL并没有这么实现。 using System.Collections.Generic; 2: //using System.Windows.Threading; 3: 4: namespace System.Windows 5: {
6: class DependencyObject 7: {
8: //依赖属性其实终究要DependencyObject和DependencyProperty成对才能算得上真正的DependencyProperty 9: static Dictionary<Type,Dictionary<string,DependencyProperty>> propertyDeclarations = new Dictionary<Type,DependencyProperty>>(); //该依赖属性的键值对,键为DependencyProperty,值为object 11: private Dictionary<DependencyProperty,255);">object> properties = new Dictionary<DependencyProperty,255);">object>(); 12: 13: //是否已密封,没有实现DependencyObject层次的IsSealed判断 14: bool IsSealed {
15: get { false; }
16: } 17: 18: //获取该DependencyObject的DependencyObjectType 19: public DependencyObjectType DependencyObjectType {
20: get { return DependencyObjectType.FromSystemType (GetType()); }
21: } 22: 23: //根据该依赖属性名,清除它的值 void ClearValue(DependencyProperty dp) 25: {
26: if (IsSealed) 27: throw new InvalidOperationException ("Cannot manipulate property values on a sealed DependencyObject");
29: properties[dp] = null; 30: } 31: 32: //根据该依赖属性DependencyPropertyKey,清除它的值 33: void ClearValue(DependencyPropertyKey key) 34: {
35: ClearValue (key.DependencyProperty); 36: } 37: 38: //根据该依赖属性名,强制值 39: void CoerceValue (DependencyProperty dp) 40: {
41: PropertyMetadata pm = dp.GetMetadata (this); 42: if (pm.CoerceValueCallback != null) 43: pm.CoerceValueCallback (this,GetValue (dp)); 44: } 45: 46: sealed override bool Equals (object obj) 47: {
48: new NotImplementedException("Equals");
49: } 50: 51: int GetHashCode () 52: {
53: "GetHashCode"); 54: } 55: 56: //得到本地值的枚举器 57: public LocalValueEnumerator GetLocalValueEnumerator() 58: {
59: new LocalValueEnumerator(properties); 60: } 61: 62: //根据依赖属性名获取值 63: object GetValue(DependencyProperty dp) 64: {
65: object val = properties[dp]; 66: return val == null ? dp.DefaultMetadata.DefaultValue : val; 67: } 68: 69: 70: void InvalidateProperty(DependencyProperty dp) 71: {
72: "InvalidateProperty(DependencyProperty dp)"); 73: } 74: 75: //当属性值改变时,触发回调 76: protected virtual void OnPropertyChanged(DependencyPropertyChangedEventArgs e) 77: {
78: PropertyMetadata pm = e.Property.GetMetadata (this); 79: if (pm.PropertyChangedCallback != null) 80: pm.PropertyChangedCallback (81: }82:83: //提供一个外界查看LocalValue的接口84: object ReadLocalValue(DependencyProperty dp) |
