依赖属性之“风云再起”四
十. PropertyMetadata测试代码
public static DependencyProperty Register(string name, Type propertyType,Type ownerType, PropertyMetadata typeMetadata,ValidateValueCallback validateValueCallback);
public PropertyMetadata(object defaultValue,PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);
public FrameworkPropertyMetadata(object defaultValue,FrameworkPropertyMetadataOptions flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback,bool isAnimationProhibited, UpdateSourceTrigger defaultUpdateSourceTrigger);
1: class TestDepObj : DependencyObject
2: {
3: public static readonly DependencyProperty TestProp1 = DependencyProperty.Register("property1", typeof(string), typeof(TestDepObj));
4: public static readonly DependencyProperty TestProp2 = DependencyProperty.Register("property2", typeof(string), typeof(TestDepObj));
5: public static readonly DependencyProperty TestProp3 = DependencyProperty.Register("property3", typeof(string), typeof(TestDepObj));
6:
7: public static readonly DependencyProperty TestProp4 = DependencyProperty.Register("property4", typeof(string), typeof(TestDepObj), new PropertyMetadata("default", changed, coerce));
8:
9: static void changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
10: static object coerce(DependencyObject d, object baseValue) { return baseValue; }
11: }
12:
13: class TestSubclass : TestDepObj
14: {
15: }
1: //首先我们自定义一个元数据类,继承自我们刚创建的PropertyMetadata类
2: public class PropertyMetadataPoker : PropertyMetadata
3: {
4:
5: public bool BaseIsSealed
6: {
7: get { return base.IsSealed; }
8: }
9:
10: public void CallApply()
11: {
12: OnApply(TestDepObj.TestProp1, typeof(TestDepObj));
13: }
14:
15: public void CallMerge(PropertyMetadata baseMetadata, DependencyProperty dp)
16: {
17: Merge(baseMetadata, dp);
18: }
19:
20: protected override void Merge(PropertyMetadata baseMetadata, DependencyProperty dp)
21: {
22: Console.WriteLine(Environment.StackTrace);
23: base.Merge(baseMetadata, dp);
24: }
25:
26: protected override void OnApply(DependencyProperty dp, Type targetType)
27: {
28: //
29: base.OnApply(dp, targetType);
30: Console.WriteLine("IsSealed in OnApply? {0}", IsSealed);
31: Console.WriteLine(Environment.StackTrace);
32: }
33: }
1: [Test]
2: public void DefaultValues()
3: {
4: //首先看看元数据的默认值
5: PropertyMetadataPoker m = new PropertyMetadataPoker();
6: Assert.AreEqual(null, m.DefaultValue);
7: Assert.AreEqual(null, m.PropertyChangedCallback);
8: Assert.AreEqual(null, m.CoerceValueCallback);
9: }
1: [Test]
2: public void IsSealed()
3: {
4: //测试元数据是否密封,这个很重要,因为封闭之后就不能修改了,除非用OverrideMetadata或者AddOwner
5: PropertyMetadataPoker m;
6:
7: Console.WriteLine(1);
8: // 直接调用 OnApply 查看元数据是否密封
9: m = new PropertyMetadataPoker();
10: Assert.IsFalse(m.BaseIsSealed);
11: m.CallApply();
12: Assert.IsFalse(m.BaseIsSealed);
13:
14: Console.WriteLine(2);
15: // 直接 OverrideMetadata
16: m = new PropertyMetadataPoker();
17: TestDepObj.TestProp1.OverrideMetadata(typeof(TestSubclass), m);
18: Assert.IsTrue(m.BaseIsSealed);
19:
20: Console.WriteLine(3);
21: // 调用 DependencyProperty.AddOwner, 通过这种方式 OverrideMetadata
22: m = new PropertyMetadataPoker();
23: TestDepObj.TestProp2.AddOwner(typeof(TestSubclass), m);
24: Assert.IsTrue(m.BaseIsSealed);
25:
26: Console.WriteLine(4);
27: // 最后, 调用DependencyProperty.Register时传入元数据
28: m = new PropertyMetadataPoker();
29: DependencyProperty.Register("xxx", typeof(string), typeof(TestDepObj), m);
30: Assert.IsTrue(m.BaseIsSealed);
31: }
1: [Test]
2: public void TestAddOwnerResult()
3: {
4: //测试AddOwner后的DependencyProperty是否和原来的DependencyProperty是同一个DependencyProperty
5: PropertyMetadataPoker m = new PropertyMetadataPoker();
6: DependencyProperty p = TestDepObj.TestProp3.AddOwner(typeof(TestSubclass), m);
7:
8: //结果是同一个DependencyProperty
9: Assert.AreSame(p, TestDepObj.TestProp3);
10: }
1: [Test]
2: [ExpectedException(typeof(InvalidOperationException))]
3: public void ModifyAfterSealed1()
4: {
5: //首先实例化元数据并注册依赖属性时作为参数传入
6: PropertyMetadataPoker m = new PropertyMetadataPoker();
7: DependencyProperty.Register("p1", typeof(string), typeof(TestDepObj), m);
8: Assert.IsTrue(m.BaseIsSealed);
9:
10: //由于元数据已密封,所以抛出如下错误信息:Cannot change metadata once it has been applied to a property
11: m.CoerceValueCallback = null;
12: }
1: [Test]
2: [ExpectedException(typeof(InvalidOperationException))]
3: public void ModifyAfterSealed2()
4: {
5: //首先实例化元数据并注册依赖属性时作为参数传入
6: PropertyMetadataPoker m = new PropertyMetadataPoker();
7: DependencyProperty.Register("p2", typeof(string), typeof(TestDepObj), m);
8: Assert.IsTrue(m.BaseIsSealed);
9:
10: //由于元数据已密封,所以抛出如下错误信息:Cannot change metadata once it has been applied to a property
11: m.PropertyChangedCallback = null;
12: }
1: [Test]
2: [ExpectedException(typeof(InvalidOperationException))]
3: public void ModifyAfterSealed3()
4: {
5: //首先实例化元数据并注册依赖属性时作为参数传入
6: PropertyMetadataPoker m = new PropertyMetadataPoker();
7: DependencyProperty.Register("p3", typeof(string), typeof(TestDepObj), m);
8: Assert.IsTrue(m.BaseIsSealed);
9:
10: //由于元数据已密封,所以抛出如下错误信息:Cannot change metadata once it has been applied to a property
11: m.DefaultValue = "hi";
12: }
1: [Test]
2: public void TestMerge()
3: {
4: //需要注意的是:在元数据密封了以后就会抛出错误
5: PropertyMetadataPoker m = new PropertyMetadataPoker();
6: m.CallMerge(TestDepObj.TestProp4.GetMetadata(typeof(TestDepObj)), TestDepObj.TestProp4);
7: Assert.AreEqual("default", m.DefaultValue);
8: Assert.IsNotNull(m.CoerceValueCallback);
9: Assert.IsNotNull(m.PropertyChangedCallback);
10:
11: m = new PropertyMetadataPoker();
12: m.DefaultValue = "non-default";
13: m.CallMerge(TestDepObj.TestProp4.GetMetadata(typeof(TestDepObj)), TestDepObj.TestProp4);
14: Assert.AreEqual("non-default", m.DefaultValue);
15: Assert.IsNotNull(m.CoerceValueCallback);
16: Assert.IsNotNull(m.PropertyChangedCallback);
17:
18: //我们知道元数据包括DefaultValue、 coerce 和 property changed等
19: //这里我们就不一一测试了,其他测试结果都是一样的
20: }
1: [Test]
2: [ExpectedException(typeof(ArgumentException))]
3: public void TestSetDefaultToUnsetValue()
4: {
5: //默认值是不能被设置成Unset的
6: PropertyMetadata m = new PropertyMetadata();
7: m.DefaultValue = DependencyProperty.UnsetValue;
8: }
9:
10: [Test]
11: [ExpectedException(typeof(ArgumentException))]
12: public void TestInitDefaultToUnsetValue()
13: {
14: //默认值是不能被设置成Unset的
15: new PropertyMetadata(DependencyProperty.UnsetValue);
16: }
十一. PropertyMetadata实现代码
1: namespace System.Windows
2: {
3: //依赖属性三大回调委托:PropertyChangedCallback、CoerceValueCallback和ValidateValueCallback
4: public delegate void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e);
5: public delegate object CoerceValueCallback(DependencyObject d, object baseValue);
6: public delegate bool ValidateValueCallback(object value);
7:
8: public class PropertyMetadata
9: {
10: private object defaultValue;
11: private bool isSealed;
12: private PropertyChangedCallback propertyChangedCallback;
13: private CoerceValueCallback coerceValueCallback;
14:
15: //返回该元数据是否已密封
16: protected bool IsSealed
17: {
18: get { return isSealed; }
19: }
20:
21: //获取和设置元数据默认值
22: public object DefaultValue
23: {
24: get { return defaultValue; }
25: set
26: {
27: if (IsSealed)
28: throw new InvalidOperationException("Cannot change metadata once it has been applied to a property");
29: if (value == DependencyProperty.UnsetValue)
30: throw new ArgumentException("Cannot set property metadata's default value to 'Unset'");
31:
32: defaultValue = value;
33: }
34: }
35:
36: //ChangedCallback委托赋值,注意检查元数据是否已经密封
37: public PropertyChangedCallback PropertyChangedCallback
38: {
39: get { return propertyChangedCallback; }
40: set
41: {
42: if (IsSealed)
43: throw new InvalidOperationException("Cannot change metadata once it has been applied to a property");
44: propertyChangedCallback = value;
45: }
46: }
47:
48: //CoerceValueCallback委托赋值,注意检查元数据是否已经密封
49: public CoerceValueCallback CoerceValueCallback
50: {
51: get { return coerceValueCallback; }
52: set
53: {
54: if (IsSealed)
55: throw new InvalidOperationException("Cannot change metadata once it has been applied to a property");
56: coerceValueCallback = value;
57: }
58: }
59:
60: #region PropertyMetadata构造函数,根据不同参数做初始化操作
61: public PropertyMetadata()
62: : this(null, null, null)
63: {
64: }
65:
66: public PropertyMetadata(object defaultValue)
67: : this(defaultValue, null, null)
68: {
69: }
70:
71: public PropertyMetadata(PropertyChangedCallback propertyChangedCallback)
72: : this(null, propertyChangedCallback, null)
73: {
74: }
75:
76: public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback)
77: : this(defaultValue, propertyChangedCallback, null)
78: {
79: }
80:
81: public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback)
82: {
83: if (defaultValue == DependencyProperty.UnsetValue)
84: throw new ArgumentException("Cannot initialize property metadata's default value to 'Unset'");
85:
86: this.defaultValue = defaultValue;
87: this.propertyChangedCallback = propertyChangedCallback;
88: this.coerceValueCallback = coerceValueCallback;
89: }
90: #endregion
91:
92: //合并元数据
93: protected virtual void Merge(PropertyMetadata baseMetadata, DependencyProperty dp)
94: {
95: if (defaultValue == null)
96: defaultValue = baseMetadata.defaultValue;
97: if (propertyChangedCallback == null)
98: propertyChangedCallback = baseMetadata.propertyChangedCallback;
99: if (coerceValueCallback == null)
100: coerceValueCallback = baseMetadata.coerceValueCallback;
101: }
102:
103: protected virtual void OnApply(DependencyProperty dp, Type targetType)
104: {
105: //留给子类来实现吧!
106: }
107:
108: //合并元数据并密封
109: internal void DoMerge(PropertyMetadata baseMetadata, DependencyProperty dp, Type targetType)
110: {
111: Merge(baseMetadata, dp);
112: OnApply(dp, targetType);
113: isSealed = true;
114: }
115: }
116: }
依赖属性之“风云再起”四相关推荐
- WPF基础到企业应用系列8——依赖属性之“风云再起”
一. 摘要 首先圣殿骑士很高兴"WPF 基础到企业应用系列" 能得到大家的关注.支持和认可.看到很多朋友留言希望加快速度的问题,我会尽力的,对你们的热情关注也表示由衷的感谢.这段时 ...
- 依赖属性之“风云再起”五
十二. 其他协助类测试代码 这里就简单写一下对DependencyObjectTypeTest的测试代码: 1: using System; 2: using System.Windows; 3: u ...
- 依赖属性之“风云再起”三
八. DependencyObject测试代码 在写DependencyObject测试代码之前,我们先看一下它到底有哪些成员和方法,如下图: 通过上面的这幅图,我们知道它的主要功能包括:各种依赖属性 ...
- 依赖属性之“风云再起”二
五. 引入测试驱动开发 1,引入概念 由于本篇的依赖属性体系是基于测试驱动开发完成的,所以我们就先来看一下什么叫测试驱动开发:测试驱动开发的基本思想就是在开发功能代码之前, 先编写测试代码.也就是说在 ...
- WPF入门教程系列十四——依赖属性(四)
六.依赖属性回调.验证及强制值 我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤: 借用一个常见的图例,介绍一下WPF属性系统对依赖属性操作的基本步骤: 第一步,确定Base ...
- WPF入门教程(七)---依赖属性(3)(转)
WPF入门教程(七)---依赖属性(3) 2018年08月24日 08:33:43 weixin_38029882 阅读数:50 四. 只读依赖属性 在以前在对于非WPF的功能来说,对于类的属性的封装 ...
- 初步了解WPF依赖属性
一 依赖属性 在WPF库实现中,依赖属性使用普通的C#属性进行了包装,使得我们可以通过和以前一样的方式来使用依赖属性.但必须明确,在WPF中我们大多数都在使用依赖属性,而不是使用属性.依赖属性重要性在 ...
- WPF入门教程系列十三——依赖属性(三)
四. 只读依赖属性 在以前在对于非WPF的功能来说,对于类的属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只 ...
- WPF快速入门系列(2)——深入解析依赖属性
一.引言 感觉最近都颓废了,好久没有学习写博文了,出于负罪感,今天强烈逼迫自己开始更新WPF系列.尽管最近看到一篇WPF技术是否老矣的文章,但是还是不能阻止我系统学习WPF.今天继续分享WPF中一个最 ...
最新文章
- c bool 类型检查_C语言和C+的区别是什么?8个点通俗易懂的告诉你!
- Android 实现边听边录音探究
- uva-10152-乌龟排序
- 【CyberSecurityLearning 52】Web架构安全分析(web工作机制、HTTP协议)
- k8s修改kube-apiserver的service-node-port-range端口范围
- 本案例通过ArrayList集合来显示Collection接口中的共性函数
- python循环结构代码_Python --- 程序的循环结构
- vue全局引入字体并使用
- 图解通信原理与案例分析-34:车联网中的系统架构与主要的通信技术
- 显卡简介,显卡怎么查看
- IE与非IE浏览器调用PC摄像头拍摄并且上传
- 匈牙利命名法(Hungarian Notation)
- JavaScript 高级
- 服务器名称没有显示,远程服务器名称问题没有解决
- 程序员不能忍996了!发起抗议网站,GitHub一小时破千星
- 笔记本win10相机打不开 无法启动 显示灰色相机
- 计算机夏令营英语自我介绍,夏令营英文自我介绍范文5篇
- Highchart 改编风力风向图
- Samba服务+Samba实验
- 对于机械键盘的一些见解(转载)