CLR属性为C#自带的机制,而依赖属性目前多应用于WPF项目中依赖属性是通过对属性进行包装后的技术,主要目的
1. 了解决使用继承造成的复杂层次结构;
- 解决属性多次集成使用造成的内存暴涨
-
依赖属性
定义并注册依赖属性
- 约定依赖属性需要以属性名称开头,以xxxProperty结尾
- 注册依赖属性时,需要指定
- 属性名称
- 属性类型
- 拥有的类
- 默认值
验证回调函数,通常用于验证相关数据是否有效
public class MyProdp : DependencyObject // 必须继承于该属性
{
// 定义包装属性类
public string MyName
{
get { return (string)GetValue(MyNameProperty); }
set { SetValue(MyNameProperty, value); }
}
// Using a DependencyProperty as the backing store for MyName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyNameProperty =
DependencyProperty.Register(
"MyName",// 属性名称
typeof(string),// 属性类型
typeof(MyProdp),// 属性拥有者
new PropertyMetadata(string.Empty),//默认值
(objec) =>// 验证回调函数
{
return true;
}
);
}
依赖属性的获取的优先级,从低到高
- 默认值
- 上级元素继承而来的值
- DefaultStyle
- 由Style Trigger设置值
- 模版触发器 Template Trigger
- StyleTrigger
- Implicit Style
- 上级元素的 Template 设置的值
- 即本地值
- 由动画过程控制的只
- WPF属性系统强制值
- 依赖属性的使用
- 一般配合绑定进行操作
-
依赖属性存储赋值原理
参考书籍深入浅出WPF
DependencyProperty.Register 创建一个DependencyPropert属性,
- 该类型中使用:_name.getHashCode^_ownerType.GetHashCode重FromNamKey的HashCode
- 并在静态属性HashTable PropertyFromName中,设置PropertyFromName[hashCode]=dp,这样就全局保存了该依赖属性。
- 对依赖属性的访问,可通过HashTable快速访问,但是DependencyPropert的hashCode返回的是GloableIndex,该Index确保每个DependencyProperty的实例是唯一的。
- DependencyObject 提供GetValue(XXXProperty),SetValue(XXXProperty)来操作依赖属性
- 在GetValue方法内部通过DependcuyProperty的GloableIndex再EffectiveValueEnty[] 数组内查找相关的值
- 在SetValue方法中,
- 首先判断值是否为UnsetValue,如果是则清空现有值
- 检查EffectiveValueEntry数组中是否已经有相关的值,有就改写,无就新增
- 调用UpdateEffective对新值进行处理。
附加属性
属性本身不属于该对象,只是后续因为需求而将该属性附加到该对象中;
1. 定义附加属性 ```csharp public static int GetAttach(DependencyObject obj) { return (int)obj.GetValue(AttachProperty); }
public static void SetAttach(DependencyObject obj, int value) { obj.SetValue(AttachProperty, value); }
// Using a DependencyProperty as the backing store for Attach. This enables animation, styling, binding, etc… public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached(“Attach”, typeof(int), typeof(MyProdp), new PropertyMetadata(0));
1. 使用附加属性
```csharp
Student student = new Student() { Name = "张鑫" };// Studetn为DependencyObject
MyProdp.SetGradeDp(student, 1);// 将附加属性绑定到Student的容器中
MessageBox.Show(string.Format("学生姓名:{0},年级:{1}", student.Name, MyProdp.GetGradeDp(student)));// 从student中查找相关的附加属性
- 用途及意义
- 可以在父级控件中定义子元素可能会用到的属性,而子级元素使用是无需考虑继承
- 子元素可以动态添加多种附加属性,增加了代码的灵活性
- 区别于依赖属性,附加属性只是把EffectiveValue的值存储到了子级元素中
依赖属性值验证
在注册依赖属性是,可以注册相关的验证回调,该回调不在元数据中 ```csharp public static readonly DependencyProperty AgeProperty = DependencyProperty.Register(“Age”, typeof(int), typeof(Student), new PropertyMetadata(0) {
}, validateValueCallback: (obj) => { // 注册验证回调 int studentAge = 0; if (int.TryParse(obj.ToString(), out studentAge)) { return studentAge >= 0 && studentAge < 150; }; return false; }); ```