wpf控件开发基础(4) -属性系统(3)
知识回顾
接上篇,上篇我们真正接触到了依赖属性的用法,以及依赖属性的属性元数据的用法,并且也实实在在地解决了之前第二篇提到的一系列问题.来回顾一下
- 属性默认值
- 属性变更通知
- 属性强制回调
本篇将继续讨论上一篇提到的问题,主题依然是属性元数据.
内容概要
- 属性值验证
- 默认值问题
- 依赖属性的不变与可变
- 属性元数据的唯一性
- 重写属性元数据
- 改写属性元数据
一.属性值验证
依赖属性具备属性验证的功能,其也会对依赖属性默认值进行验证,在DependencyProperty的Register方法中最后一个参数为ValidateValueCallback,用于属性值验证,如下代码
public static readonly DependencyProperty AgeProperty =
DependencyProperty.Register("Age", typeof(int), typeof(DPCustomPeople),
new PropertyMetadata(1), new ValidateValueCallback(AgeValidateValueCallback)); public virtual int Age
{
get { return (int)GetValue(AgeProperty); }
set { SetValue(AgeProperty, value); }
} public static bool AgeValidateValueCallback(object value)
{
int age=(int)value;
if (age < 1) return false;
return true;
}
ValidateValueCallback有一个传入的参数(即依赖属性值)和一个返回值(表示属性值是否是正确的).
注意:
1.当返回值为false的时候,将会抛出异常
2.不要试图在该回调方法中校正传入的值类型(即使引用类型也不符合逻辑),其主要职责在于验证.
此功能用的不是很频繁,因为返回false会抛异常,还要额外处理.再说强制回调方法也可以处理.
二.默认值问题
上一篇有讲到依赖属性的默认值问题
在构造函数里给属性赋值并不能解决问题(这是依赖属性默认值带来的额外问题,因为其是静态属性)
类继承带来的默认值重写问题,看以下代
public class RootClass
{
public RootClass()
{
this.Name = "RootClass";
}
public string Name { get; set; }
} public class SubClass : RootClass
{
public SubClass()
{
this.Name = "SubClass";
}
}
上面代码应该没问题,但如果这样就有问题了
public class RootClass
{
public RootClass()
{
Name = "RootClass";
}
public static string Name { get; set; }
} public class SubClass : RootClass
{
public SubClass()
{
Name = "SubClass";
}
}
如果是静态属性的话,子类一旦改写就会改变父类,破坏内部逻辑
那么就需要保证属性在每个类默认值的唯一性.
三.依赖属性的不变与可变
上篇有提到过这样一句话
(依赖属性)属性名字,属性类型,属性所有者类型一经注册将无法更改
这便不可变的地方,即使在子类重写也不行.
但依赖属性的默认值是可以修改的,修改的前提是保证父类的属性默认值不被影响,上篇我们有提出疑问,给默认值为什么需要属性元数据(PropertyMetadata),以下的代码也应该走的通
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(DPCustomPeople),
string.Empty);
是的,若依赖属性内部有一个列表维护默认值,也保证了在不同类型中默认值不会发生错误.这样的代码是没问题的,但不要忘了,还有属性变更通知和属性强制回调.PropertyMetadata把依赖属性可变的行为全部抽取出来了,我想这样做的原因可以保持依赖属性功能的清晰程度(个人猜想,但确实有这样的效果).那么就意味着我们可以重写属性元数据.
四.属性元数据的唯一性
DependencyProperty提供了OverrideMetadata方法重写属性元数据,但一个依赖属性在同一个类中不允许重写,即在同一类型中,保证属性元数据在依赖属性中的唯一性,如下代码是错误的
public class DPCategory : DependencyObject
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(DPCategory),
new PropertyMetadata(string.Empty)); public void TestOverrideMetadata()
{
//wrong
NameProperty.OverrideMetadata(typeof(DPCategory), new PropertyMetadata("WPF"));
}
}
将会抛出异常
五.重写属性元数据
继承的子类允许重写属性元数据,如下代码
public class DPWPFCategory : DPCategory
{
public void TestOverrideMetadata()
{
NameProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata("WPF"));
Console.WriteLine(NameProperty.GetMetadata(typeof(DPWPFCategory)).DefaultValue);
//output 30
}
}
注意:在重写属性元数据时,应该要知道一下规则.
1.重写元数据是一个以重写元数据为主的合并的过程,即子类的重写后的元数据会与父类的进行合并
我们在父类定义一个Group的依赖属性
public string Group
{
get { return (string)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value); }
}
public static readonly DependencyProperty GroupProperty =
DependencyProperty.Register("Group", typeof(string), typeof(DPCategory),
new PropertyMetadata(string.Empty,new PropertyChangedCallback(GroupPropertyChangedCallback))); public static void GroupPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine(e.NewValue);
}
然后在子类重写此依赖属性的元数据
public void TestOverrideMergeMetadata()
{
GroupProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata("Computer Technology"));
Console.WriteLine(this.Group);
this.Group = "Technology";
}
输出结果,当属性值发生变化时,父类的属性变更通知回调方法就会触发
2.实例匹配(Type.IsAssignableFrom 返回为true)
注意:要重写的父类属性元数据类型必须要是重写的属性元数据的父类或者与之类型相同.如下为属性元数据的继承关系
可以看出如果用FrameworkPropertyMetadata来重写的话是最保险的
如下示例
public int Order
{
get { return (int)GetValue(OrderProperty); }
set { SetValue(OrderProperty, value); }
} public static readonly DependencyProperty OrderProperty =
DependencyProperty.Register("Order", typeof(int), typeof(DPCategory), new UIPropertyMetadata(0));
//UIPropertyMetadata
注意父类的属性元数据为UIPropertyMetadata,以下子类重写的属性元数据类型为PropertyMetadata 即会报错.
public void TestOverrideDriveMetadata()
{
OrderProperty.OverrideMetadata(typeof(DPWPFCategory), new PropertyMetadata(1));
//wrong
//must >=UIPropertyMetadata
}
输出
六.改写属性元数据
改写与重写有几点不同.
- 改写是将已存在的依赖属性添加到不同类型当中
- 改写不是一个合并属性元数据的过程,改写后的是全新的
如下:
为一个全新的类型添加已有依赖属性,并重写属性元数据,重写后将不会触发DPCategory类型的GroupProperty属性变更通知,不会影响原依赖属性逻辑
public class DPGroup:DependencyObject
{
public static readonly DependencyProperty GroupProperty =
DPCategory.GroupProperty.AddOwner(typeof(DPGroup),
new PropertyMetadata("Technology"));
public string Group
{
get { return (string)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value); }
} public void TestAddOwnerMetadata()
{
Console.WriteLine(Group);
this.Group = "Computer Technology";
}
}
注意:如果在子类进行此操作,将与重写效果一样
本篇主要讲到了属性元数据的一些特点及注意点.FrameworkPropertyMetadata还有许多特性,但必须有实际场景结合.所以这里无法展开.讲了这么多貌似都没触及到WPF什么事,这部分也是比较枯燥,但却非常重要.下篇继续,然后依赖属性就告一段落.
wpf控件开发基础(4) -属性系统(3)的更多相关文章
- wpf控件开发基础(3) -属性系统(2)
原文:wpf控件开发基础(3) -属性系统(2) 上篇说明了属性存在的一系列问题. 属性默认值,可以保证属性的有效性. 属性验证有效性,可以对输入的属性进行校验 属性强制回调, 即不管属性有无发生变化 ...
- wpf控件开发基础(2) -属性系统(1)
原文:wpf控件开发基础(2) -属性系统(1) 距离上篇写的时间有1年多了.wpf太大,写的东西实在太多,我将依然围绕着自定义控件来展开与其相关的技术点. 也欢迎大家参与讨论.这篇我们将要讨论的是W ...
- wpf控件开发基础
wpf控件开发基础(3) -属性系统(2) http://www.cnblogs.com/Clingingboy/archive/2010/02/01/1661370.html 这个有必要看看 wpf ...
- wpf控件开发基础(5) -依赖属性实践
原文:wpf控件开发基础(5) -依赖属性实践 知识回顾 接上篇,回顾这三篇讲了什么东西 首先说明了属性的现存问题,然后介绍了依赖属性的基本用法及其解决方案,由于依赖属性以静态属性的方式存在,进而又介 ...
- asp.net控件开发基础(1)(转)原文更多内容
asp.net本身提供了很多控件,提供给我们这些比较懒惰的人使用,我认为控件的作用就在此,因为我们不想重复工作,所以要创建它,这个本身便是一个需求的关系,所以学习控件开发很有意思. wrox网站上有本 ...
- WPF控件开发(2) 自动完成(AutoComplete)-1
自动完成功能使用范围很广,多以TextBox或ComboBox的形式出现,在输入的同时给予候选词,候选词一般有两种方式获取. 一种类似Baidu,Google,Bing之类的搜索引擎所用的直接给予前十 ...
- 跟我一起学WPF(2):WPF控件基础
WPF控件简介 通过上一篇XAML语言的介绍,我们知道,XAML是一个树形结构,同样,WPF控件作为构成整个XAML树的一部分,也是一个树形结构.我们看一个简单的例子. <Button.Cont ...
- 浅谈Winform控件开发(一):使用GDI+美化基础窗口
写在前面: 本系列随笔将作为我对于winform控件开发的心得总结,方便对一些读者在GDI+.winform等技术方面进行一个入门级的讲解,抛砖引玉. 别问为什么不用WPF,为什么不用QT.问就是懒, ...
- C# Winform开发以及控件开发的需要注意的,被人问怕了,都是基础常识
我是搞控件开发的,经常被人问,所以把一些问题记录了下来!如果有人再问,直接把地址丢给他看. 一. 经常会有人抱怨Winform界面闪烁,下面有几个方法可以尽可能的避免出现闪烁 1.控件的使用尽量以纯色 ...
随机推荐
- 【例题 6-8 UVA - 548】Tree
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 后序遍历的最后一个是根节点. ->然后在中序遍历中找到这个节点. 分为左右两段. 然后递归上述操作就好. 题目描述好坑啊. 原 ...
- TOP全异步模式
Top全异步方式调用技术方案 背景:目前top通过servlet3.0技术结合异步管道化框架做到半异步调用,半异步调用采用异步线程同步调用后端的方式来做api call @飞不起的奥特曼 的部分文档) ...
- 自己定义Dialog的具体步骤(实现自己定义样式一般原理)
转载请标注转载http://blog.csdn.net/oqihaogongyuan/article/details/50958659 自己定义Dialog的具体步骤(实现自己定义样式一般原理) ...
- Launcher Activity在开机时重新启动两次解决的方法
今天在看log的时候发现,Launcher activity会被onDestroy掉一次.然后再重新启动. 可能原因推測: 1.横竖屏切换 2.MCC MNC等Configuration改变引起的 M ...
- ALERT日志中常见监听相关报错之二:ORA-3136错误的排查
最近在多个大型系统中遇到此问题,一般来说假设client未反映异常的话能够忽略的. 假设是client登陆时遇到ORA-12170: TNS:Connect timeout occurred,能够參考 ...
- NoSql中的B-tree、B+tree和LSM-tree 分类: B7_HBASE 2015-03-15 18:27 85人阅读 评论(0) 收藏
总结: 1.B+树将数据完全排序,读数据时很快,但当要修改数据时,就需要将新入数据下面的数据重新排位,特别是当写入的数据排在较高的位置时,需要大量的移位操作才能完成写入. 2.SLM牺牲部分的读性能, ...
- Android隐藏输入法
输入法隐藏两种方式: /** * 隐藏输入法 * * @param myActivity */ public static void hideInput(Activity myActivity,Edi ...
- ImageButton按压效果失效
LinearLayout中ImageButton的按压效果不起作用,如图 布局如下: <LinearLayout android:id="@id/ll_add_reply_face&q ...
- CSS边框作图
原文 简书原文:https://www.jianshu.com/p/537a878304f2 大纲 1.border-style的值 2.利用border作图——基本图形 3.利用border作图—— ...
- jsp页面无法解析EL表达式问题
Servlet版本的问题.原来Servlet中可以设定是否解析EL表达式,只有2.4版本的Servlet默认是解析EL表达式的,而其他版本是默认不解析EL表达式.于是把web.xml中使用的2.5版本 ...