依赖属性之“风云再起”三

前端之家收集整理的这篇文章主要介绍了依赖属性之“风云再起”三前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

八. DependencyObject测试代码

@H_502_2@ 在写DependencyObject测试代码之前,我们先看一下它到底有哪些成员和方法,如下图:
@H_502_2@

2010-8-26

@H_502_2@   通过上面的这幅图,我们知道它的主要功能包括:各种依赖属性的GetValue、SetValue操作(核心功能)和ClearValue、 CoerceValue、GetLocalValueEnumerator、ReadLocalValue等操作。为了测试这些功能,我们首先创建几个 类,第一个类X,内部首先注册一个附加依赖属性,我们都知道,不管是附加依赖属性还是依赖属性,都需要使用到GetValue和SetValue操作,只 是一个封装成了属性,而另一个封装成了静态方法而已。第二个类直接继承自我们前面在实现DependencyProperty时创建的 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:     {
@H_403_156@  24:         string)obj.GetValue(BProperty);
  25:     }
  26: 
  27: }
  28: 
  29: class Y : DependencyObject {
  30: }
@H_502_2@ 第三个类则是为了直接测试注册一个依赖属性,这个类首先继承自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);
@H_403_156@  24:           return value;
  25:       }
  27:       bool IsValidValue(value)
  28:       {
  29:           Console.WriteLine("验证值是否通过,如果返回True表示验证通过,否则会以异常的形式暴露: {0}",255);">value);
  30:           true;
  31:       }
  32: 
  33:   }
@H_502_2@ 首先我们先写测试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: }
@H_502_2@ 由于这里是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:     }
@H_502_2@   通过前面的图,大家可以看到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:     }
@H_502_2@ 还有几个功能,既然Mono也没做研究,我们也就不费那个力气了,接下来我们就看看刚才实现的DependencyObject代码吧!

九. DependencyObject实现代码

@H_502_2@ 通过前面的测试用例,DependencyObject类的基本功能已经完成,不过我们要注意几个要点:
1,依赖属性其实终究要DependencyObject和DependencyProperty成对才能算得上真正的DependencyProperty @H_502_2@ 2,不管是Register、RegisterAttached、RegisterAttachedReadOnly还是 RegisterReadOnly操作,我们都要通过DependencyObject来操作DependencyProperty的值,也就是通过 DependencyObject这个外部接口来操作,DependencyProperty只负责注册和内部处理,不负责外部接口。 @H_502_2@ 3,在DependencyObject中提供了几个操作LocalValue的接口的接口,其中包括ReadLocalValue、GetLocalValueEnumerator、CoerceValue和ClearValue等。 @H_502_2@ 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)
  85:         {
  86:             object val = properties[dp];
  87:             null ? DependencyProperty.UnsetValue : val;
  88:         }
  89: 
  90:         //根据依赖属性名设置其值
  91:         void SetValue(DependencyProperty dp,255);">value)
  92:         {
  93:             if (IsSealed)
  94:                 "Cannot manipulate property values on a sealed DependencyObject");
  95: 
  96:             if (!dp.IsValidType (value))
  97:                 new ArgumentException ("value not of the correct type for this DependencyProperty");
  98: 
  99:             ValidateValueCallback validate = dp.ValidateValueCallback;
 100:             if (validate != null && !validate(value))
 101:                 new Exception("Value does not validate");
 102:             else
 103:                 properties[dp] = value;
 104:         }
 105: 
 106:         //根据依赖属性DependencyPropertyKey设置其值
 107:         void SetValue(DependencyPropertyKey key,255);">value)
 108:         {
 109:             SetValue (key.DependencyProperty,255);">value);
 110:         }
 111: 
 112:         bool ShouldSerializeProperty (DependencyProperty dp)
 113:         {
 114:             new NotImplementedException ();
 115:         }
 116: 
 117:         //这里的注册实质是关联propertyDeclarations
 118:         internal void register(Type t,DependencyProperty dp)
 119:         {
 120:             if (!propertyDeclarations.ContainsKey (t))
 121:                 propertyDeclarations[t] = new Dictionary< 122:             Dictionary< 123:             if (!typeDeclarations.ContainsKey(dp.Name))
 124:             {
 125:                 typeDeclarations[dp.Name] = dp;
 126:                 //这里仍然有一些问题,期待各位共同探讨解决
 127:             }
 128:             else
 129:                 new ArgumentException("A property named " + dp.Name + " already exists on " + t.Name);
 130:         }
 131:     }
 132: }
@H_502_2@   通过前面对DependencyObject和DependencyProperty的研究之后,我们来看看最重要的一个角色,这也是微软最喜欢用的概念――元数据,如果大家研究过微软BCL的源码,应该都知道,它是贯穿于整个CLR当中的。

猜你在找的设计模式相关文章