且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-10-04 18:03:01

十二. 其他协助类测试代码

这里就简单写一下对DependencyObjectTypeTest的测试代码:
   1: using System;
   2: using System.Windows;
   3: using NUnit.Framework;
   4:  
   5: namespace TDDDependencyTest.System.Windows
   6: {
   7:     [TestFixture]
   8:     public class DependencyObjectTypeTest
   9:     {
  10:  
  11:         [Test]
  12:         public void Accessors()
  13:         {
  14:             DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj));
  15:             Assert.AreEqual("TestDepObj", t.Name);
  16:             Assert.AreEqual(typeof(TestDepObj), t.SystemType);
  17:             Assert.AreEqual(typeof(DependencyObject), t.BaseType.SystemType);
  18:         }
  19:  
  20:         [Test]
  21:         public void IsInstanceOfType()
  22:         {
  23:             DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj));
  24:             DependencyObjectType t2 = DependencyObjectType.FromSystemType(typeof(TestSubclass));
  25:             Assert.IsTrue(t.IsInstanceOfType(new TestSubclass()));
  26:             Assert.IsTrue(t2.IsSubclassOf(t));
  27:             Assert.IsFalse(t.IsSubclassOf(t2));
  28:         }
  29:  
  30:         [Test]
  31:         public void TestCache()
  32:         {
  33:             DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj));
  34:             DependencyObjectType t2 = DependencyObjectType.FromSystemType(typeof(TestDepObj));
  35:             Assert.AreSame(t, t2);
  36:         }
  37:     }
  38: }
由于它的功能比较简单,所以我们就不做过多介绍,大家想了解更多,可以参看代码。

十三. 其他协助类的实现代码

LocalValueEnumerator:手动实现一个IEnumerator来方便访问LocalValue
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Collections;
   6:  
   7: namespace System.Windows
   8: {
   9:     //手动实现一个IEnumerator来方便访问LocalValue
  10:     public struct LocalValueEnumerator : IEnumerator
  11:     {
  12:         private IDictionaryEnumerator propertyEnumerator;
  13:         private Dictionary<DependencyProperty, object> properties;
  14:  
  15:         private int count;
  16:  
  17:         internal LocalValueEnumerator(Dictionary<DependencyProperty, object> properties)
  18:         {
  19:             this.count = properties.Count;
  20:             this.properties = properties;
  21:             this.propertyEnumerator = properties.GetEnumerator();
  22:         }
  23:  
  24:         public int Count
  25:         {
  26:             get { return count; }
  27:         }
  28:  
  29:         //获取当前LocalValue
  30:         public LocalValueEntry Current
  31:         {
  32:             get
  33:             {
  34:                 return new LocalValueEntry((DependencyProperty)propertyEnumerator.Key,
  35:                   propertyEnumerator.Value);
  36:             }
  37:         }
  38:  
  39:         object IEnumerator.Current
  40:         {
  41:             get { return this.Current; }
  42:         }
  43:  
  44:  
  45:         public bool MoveNext()
  46:         {
  47:             return propertyEnumerator.MoveNext();
  48:         }
  49:  
  50:         //重置propertyEnumerator
  51:         public void Reset()
  52:         {
  53:             propertyEnumerator.Reset();
  54:         }
  55:  
  56:         public static bool operator !=(LocalValueEnumerator obj1, LocalValueEnumerator obj2)
  57:         {
  58:             throw new NotImplementedException();
  59:         }
  60:  
  61:         public static bool operator ==(LocalValueEnumerator obj1, LocalValueEnumerator obj2)
  62:         {
  63:             throw new NotImplementedException();
  64:         }
  65:  
  66:         public override bool Equals(object obj)
  67:         {
  68:             throw new NotImplementedException();
  69:         }
  70:  
  71:         public override int GetHashCode()
  72:         {
  73:             throw new NotImplementedException();
  74:         }
  75:     }
  76:  
  77:     //LocalValue实体类
  78:     public struct LocalValueEntry
  79:     {
  80:         private DependencyProperty property;
  81:         private object value;
  82:  
  83:         internal LocalValueEntry(DependencyProperty property, object value)
  84:         {
  85:             this.property = property;
  86:             this.value = value;
  87:         }
  88:  
  89:         public DependencyProperty Property
  90:         {
  91:             get { return property; }
  92:         }
  93:  
  94:         public object Value
  95:         {
  96:             get { return value; }
  97:         }
  98:  
  99:         public static bool operator !=(LocalValueEntry obj1, LocalValueEntry obj2)
 100:         {
 101:             throw new NotImplementedException();
 102:         }
 103:  
 104:         public static bool operator ==(LocalValueEntry obj1, LocalValueEntry obj2)
 105:         {
 106:             throw new NotImplementedException();
 107:         }
 108:  
 109:         public override bool Equals(object obj)
 110:         {
 111:             throw new NotImplementedException();
 112:         }
 113:  
 114:         public override int GetHashCode()
 115:         {
 116:             throw new NotImplementedException();
 117:         }
 118:     }
 119: }
 120:  
   DependencyPropertyChangedEventArgs:PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)的参数,它的第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为改变了的值。
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: namespace System.Windows
   7: {
   8:     public class DependencyPropertyChangedEventArgs
   9:     {
  10:         //第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为新值
  11:         public DependencyPropertyChangedEventArgs(DependencyProperty property, object oldValue, object newValue)
  12:         {
  13:             this.Property = property;
  14:             this.OldValue = oldValue;
  15:             this.NewValue = newValue;
  16:         }
  17:  
  18:         //注意所有的属性只对外界开放只读操作
  19:         public object NewValue
  20:         {
  21:             get;
  22:             private set;
  23:         }
  24:  
  25:         public object OldValue
  26:         {
  27:             get;
  28:             private set;
  29:         }
  30:  
  31:         public DependencyProperty Property
  32:         {
  33:             get;
  34:             private set;
  35:         }
  36:  
  37:         public override bool Equals(object obj)
  38:         {
  39:             if (!(obj is DependencyPropertyChangedEventArgs))
  40:                 return false;
  41:  
  42:             return Equals((DependencyPropertyChangedEventArgs)obj);
  43:         }
  44:  
  45:         public bool Equals(DependencyPropertyChangedEventArgs args)
  46:         {
  47:             return (Property == args.Property &&
  48:                 NewValue == args.NewValue &&
  49:                 OldValue == args.OldValue);
  50:         }
  51:  
  52:         public static bool operator !=(DependencyPropertyChangedEventArgs left, DependencyPropertyChangedEventArgs right)
  53:         {
  54:             throw new NotImplementedException();
  55:         }
  56:  
  57:         public static bool operator ==(DependencyPropertyChangedEventArgs left, DependencyPropertyChangedEventArgs right)
  58:         {
  59:             throw new NotImplementedException();
  60:         }
  61:  
  62:         public override int GetHashCode()
  63:         {
  64:             throw new NotImplementedException();
  65:         }
  66:  
  67:     }
  68: }
DependencyPropertyKey:构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata,此类只是起到了封装作用。
   1:  
   2: namespace System.Windows
   3: {
   4:     //构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata
   5:     public sealed class DependencyPropertyKey 
   6:     {
   7:         internal DependencyPropertyKey (DependencyProperty dependencyProperty)
   8:         {
   9:             this.dependencyProperty = dependencyProperty;
  10:         }
  11:  
  12:         private DependencyProperty dependencyProperty;
  13:         public DependencyProperty DependencyProperty {
  14:             get { return dependencyProperty; }
  15:         }
  16:  
  17:         public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
  18:         {
  19:             dependencyProperty.OverrideMetadata (forType, typeMetadata, this);
  20:         }
  21:     }
  22: }
  DependencyObjectType:用静态Dictionary<Type, DependencyObjectType>来存储DependencyObjectType,主要有FromSystemType、 IsInstanceOfType和IsSubclassOf三个功能。
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: namespace System.Windows
   7: {
   8:     public class DependencyObjectType
   9:     {
  10:         //键为Type(即OwnerType),值为DependencyObjectType(即ID和systemType)的键值对
  11:         private static Dictionary<Type, DependencyObjectType> typeMap = new Dictionary<Type, DependencyObjectType>();
  12:         private static int current_id;
  13:  
  14:         private int id;
  15:         private Type systemType;
  16:  
  17:         //构造函数私有,在FromSystemType里进行构造,初始化id和systemType
  18:         private DependencyObjectType(int id, Type systemType)
  19:         {
  20:             this.id = id;
  21:             this.systemType = systemType;
  22:         }
  23:  
  24:         //基类型的DependencyObjectType
  25:         public DependencyObjectType BaseType
  26:         {
  27:             get { return DependencyObjectType.FromSystemType(systemType.BaseType); }
  28:         }
  29:  
  30:         public int Id
  31:         {
  32:             get { return id; }
  33:         }
  34:  
  35:         public string Name
  36:         {
  37:             get { return systemType.Name; }
  38:         }
  39:  
  40:         public Type SystemType
  41:         {
  42:             get { return systemType; }
  43:         }
  44:  
  45:         //用静态Dictionary<Type, DependencyObjectType>来存储DependencyObjectType
  46:         public static DependencyObjectType FromSystemType(Type systemType)
  47:         {
  48:             if (typeMap.ContainsKey(systemType))
  49:                 return typeMap[systemType];
  50:  
  51:             DependencyObjectType dot;
  52:  
  53:             typeMap[systemType] = dot = new DependencyObjectType(current_id++, systemType);
  54:  
  55:             return dot;
  56:         }
  57:  
  58:         //是否是该DependencyObject的子类实例
  59:         public bool IsInstanceOfType(DependencyObject d)
  60:         {
  61:             return systemType.IsInstanceOfType(d);
  62:         }
  63:  
  64:         //该DependencyObjectType是否是传入DependencyObjectType的子实例
  65:         public bool IsSubclassOf(DependencyObjectType dependencyObjectType)
  66:         {
  67:             return systemType.IsSubclassOf(dependencyObjectType.SystemType);
  68:         }
  69:  
  70:         public override int GetHashCode()
  71:         {
  72:             throw new NotImplementedException();
  73:         }
  74:     }
  75: }
  76:  

十四. 回归并统计覆盖率

  在上面的开发过程中,我们会不断的运行和查看代码通过情况,最后我们也来看一下测试用例的总体通过情况,其实在前面已经运行过很多次了,因为每个功能都要经过”测试代码-功能代码-测试-重构“等步骤。
依赖属性之“风云再起”五
  最后也看一下代码测试覆盖率,代码测试覆盖率对一个系统或者产品来说是一个比较重要的质量指标,可以通过它看出系统的稳定性和可控性。一般在项目的开发中,我们都会以85%~90%的测试代码覆盖率作为达标的参考标准。
依赖属性之“风云再起”五
  由于MONO本身对依赖属性没有那么健全,我们也没有写那么详细的测试代码,中间直接就实现了一些功能,严格地说,所以本文并没有完全遵从正规的测试驱动开发流程。

十五. 简单验证依赖属性系统

其实通过上面的测试用例,基本就用不着再单独测试了,但鉴于覆盖率比较低的问题,所以最后我们还是来测试一下刚才构建的依赖属性系统:
   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         SimpleDPClass sDPClass = new SimpleDPClass();
   6:         sDPClass.SimpleDP = 8;
   7:         Console.ReadLine();
   8:     }
   9: }
  10:  
  11: public class SimpleDPClass : DependencyObject
  12: {
  13:     public static readonly DependencyProperty SimpleDPProperty =
  14:         DependencyProperty.Register("SimpleDP", typeof(double), typeof(SimpleDPClass),
  15:             new PropertyMetadata((double)0.0,
  16:        
  17:                 new PropertyChangedCallback(OnValueChanged),
  18:                 new CoerceValueCallback(CoerceValue)),
  19:                 new ValidateValueCallback(IsValidValue));
  20:  
  21:     public double SimpleDP
  22:     {
  23:         get { return (double)GetValue(SimpleDPProperty); }
  24:         set { SetValue(SimpleDPProperty, value); }
  25:     }
  26:  
  27:     private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  28:     {
  29:         Console.WriteLine("当值改变时,我们可以做的一些操作,具体可以在这里定义: {0}", e.NewValue);
  30:     }
  31:  
  32:     private static object CoerceValue(DependencyObject d, object value)
  33:     {
  34:         Console.WriteLine("对值进行限定,强制值: {0}", value);
  35:         return value;
  36:     }
  37:  
  38:     private static bool IsValidValue(object value)
  39:     {
  40:         Console.WriteLine("验证值是否通过,如果返回True表示验证通过,否则会以异常的形式暴露: {0}", value);
  41:         return true;
  42:     }
  43:  
  44: }
测试结果:
依赖属性之“风云再起”五
到处为止,我们这篇文章也宣告结束。

十六. 本文总结

  本篇承接上一篇WPF基础到企业应用系列7——深入剖析依赖属性的 写作风格,对上篇模拟一个WPF依赖属性的实现重现演绎了一遍,上篇是根据微软WPF的BCL源码剖析的,所以这篇我们就详细的研究一下.NET的跨平台 版本MONO关于依赖属性系统的实现。在这篇文章中,我只是起到了剖析源码的作用,就像研究微软的BCL一样,不过MONO的代码远没有微软的BCL那么 庞大,所以研究和复原起来不是很吃力。如果大家还想继续深入,可以去下载相关源码,也希望大家和我一起交流探讨。

十七. 相关代码下载

  在文章的最后,和往常一样,我们提供代码的下载,再次温馨提示:这几篇文章最重要的就是下载代码来细细研究,代码里面也添加了比较详细的注释,如果大家有什么问题,也可以直接和我联系,如果有不正确的地方也希望多多海涵并能给我及时反馈,我将感激不尽!
 依赖属性之“风云再起”五 
上图就是整个代码包的结构图,下载链接:DependencySystem.rar

十八.系列进度

前篇
· 9. WPF 基础到企业应用系列9——深入剖析WPF事件机制 (核心篇)     
·10. WPF 基础到企业应用系列10——WPF事件机制之“刨根问底”
·11. WPF 基础到企业应用系列11——深入剖析WPF命令机制 (核心篇)  
·12. WPF 基础到企业应用系列12——WPF命令之“庖丁解牛”
·13. WPF 基础到企业应用系列13——WPF Binding全接触 (核心篇)   
·14. WPF 基础到企业应用系列14——WPF Binding之“面面俱到”
中篇
· 1. 资源、样式、模板
· 2. 尺寸缩放、定位与变换元素
· 3. WPF控件分类介绍与使用技巧
· 4. 用户控件和自定义控件开发
· 5. 多语言、皮肤和主题
· 6. 2D图形
· 7. 3D图形
· 8. 动画(几种动画的应用)
· 9. 音频、视频、语音
· 10. 文档、打印、报表
后篇
· 1. Win32、Windows Form以及ActiveX之间的互用性
· 2. 构建并部署应用程序(ClickOnce部署、微软setup /InstallShield+自动更新组件)
· 3. MVC、MVP、MVVM全解析
· 4. WPF的模式讲解及实例(MVC Demo)
· 5. WPF的模式讲解及实例(MVP Demo)
· 6. WPF的模式讲解及实例(MVVM Demo)
· 7. 性能优化(WPF项目的瓶颈)
· 8.一个完整WPF项目(普通架构版)
· 9. 一个完整WPF项目(MVVM架构版)
· 10. WPF 4.0新功能
云计算专区http://home.cnblogs.com/group/CloudComputing/),如果大家有什么云计算相关的疑问或话题也可以在里面进行探讨。由于圣殿骑士以后会定格和专注于这几个方向,所以很希望同大家一起交流和进步!



















本文转自KnightsWarrior51CTO博客,原文链接:http://blog.51cto.com/knightswarrior/405236 ,如需转载请自行联系原作者