WPF 依赖属性 DependencyProperty
来源:互联网 发布:centos git使用教程 编辑:程序博客网 时间:2024/04/29 04:24
1.依赖属性介绍
在WPF中使用了更高级的依赖项属性替换了.net中的属性。依赖属性具有一些更高效的保存机制,同进支持附加功能,如 更改通知(Change Notification)以及属性值继承(在元素树中向下传递默认属性值)。依赖属性同样还是WPF中Animation,Binding,Style的重要基础。.
2.依赖属性定义
注意:只能为依赖对象(继承自DependencyObject)添加依赖属性。WPF中基础结构的关键部分中大部分都间接继承自DependencyObject类。
例子:
WPF中最常见的属性之一就是Margin属性。它在FramewordElement类中被定义,所有元素都共享自该属性。下面是FrameworkElement类的源函数
public class FrameworkElement:UIElement{ [CommonDependencyProperty] public static readonly DependencyProperty MarginProperty;}
约定在定义依赖属性时在普通属性的末尾加上单词“Property”。字段的定义使用Public static readonly。这意味着只能在FrameworkElement类的静态构造函数中对其进行设置。
3.依赖属性注册
注意DependencyProperty类没有公有的构造函数。故只能使用DependencyProperty.Register()方法来创建DependencyProperty的实例。DependencyProperty.Register()同样是一个静态的方法。下面是该方法的定义:
// // 摘要: // 使用指定的属性名称、属性类型、所有者类型、属性元数据和属性的值验证回调来注册依赖项属性。 // // 参数: // name: // 要注册的依赖项对象的名称。 // // propertyType: // 属性的类型。 // // ownerType: // 正注册依赖项对象的所有者类型。 // // typeMetadata: // 依赖项对象的属性元数据。(可选) // // validateValueCallback: // 对回调的引用,除了典型的类型验证之外,该引用还应执行依赖项对象值的任何自定义验证。(可选) // // 返回结果: // 一个依赖项对象标识符,应使用它在您的类中设置 public static readonly 字段的值。 //然后,在以后使用该标识符引用依赖项对象,用于某些操作,例如以编程方式设置其值,或者获取元数据。 public static DependencyProperty Register( string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback);
注册一个依赖属性主要有两个步骤
1.创建一个FrameworkPropertyMetadata对象,该对象指示了希望通过依赖属性来使用什么服务(如支持动画,数据绑定等)。
FrameworkPropertyMetadata的主要属性如下:
public bool AffectsArrange { get; set; } public bool AffectsMeasure { get; set; } public bool AffectsParentArrange { get; set; } public bool AffectsParentMeasure { get; set; } public bool AffectsRender { get; set; } public bool BindsTwoWayByDefault { get; set; } public UpdateSourceTrigger DefaultUpdateSourceTrigger { get; set; } public bool Inherits { get; set; } public bool IsDataBindingAllowed { get; } public bool IsNotDataBindable { get; set; } public bool Journal { get; set; } public bool OverridesInheritanceBehavior { get; set; } public bool SubPropertiesDoNotAffectRender { get; set; }
2.通过调用DependencyProperty.Register()静态方法来注册属性。
static FrameworkElement() { FrameworkPropertyMetadata metadata=new FrameworkPropertyMetadata( new Thickness(),FrameworkPropertyMetadataOptions.AffectsMeasure); MarginProperty =DependencyProperty.Register ("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid)); }
4.添加属性包装器
创建依赖属性的最后一步是使用传统的.net属性包装WPF依赖属性。注意WPF属性使用GetValue和SetValue。下面是示例:
FrameworkElement:UIElement{public Thickness Margin{set{ SetValue(MarginProperty, value); }get{return(Thickness)GetValue(MarginProperty);}} }注意:当创建属性包装器时,不应当包含任何额外的验证属性值的代码,引发事件的代码,等等。因为WPF的其他功能可能会忽略属性包装器的代码而直接调用SetValue和GetValue方法(比如在Xaml中直接为属性赋值)。事件的触发应当写在FrameworkPropertyMetadata.PropertyChangedCallback的回调函数中。
5.回调函数
在上一节中提到如果想在属性修改时能够自动引发事件,就应当实现FrameworkPropertyMetadata.PropertyChangedCallback。
这是因为在WPF中,当属性值发生变化时,依赖项属性不会自动引发事件,它们会触发一个受保护的名为OnPropertyChangedCallback()的方法。此方法通过WPF的Binding和触发器传递信息,并调用PropertyChangedCallback回调函数。
// // 摘要: // 用指定的默认值和回调初始化 System.Windows.PropertyMetadata 类的新实例。 // // 参数: // defaultValue: // 依赖项对象的默认值,通常作为某种特定类型的值提供。 // // propertyChangedCallback: // 对处理程序实现的引用,每当属性的有效值更改时,属性系统都将调用该处理程序实现。 // // coerceValueCallback: // 对处理程序实现的引用,每当属性系统对该属性调用 System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty) // 时都将调用此处理程序实现。 // // 异常: // System.ArgumentException: // defaultValue 不能设置为值 System.Windows.DependencyProperty.UnsetValue; public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);只要实现了PropertyChangedCallback 就能够实现属性值更改的自动响应。
6.属性验证
当属性值非法时,对于传统的.net属性,可以在属性设置器中捕获这类问题。在WPF中,依赖属性使用SetValue()来进行设置属性,老方法已经不再适用。原因在第4小节中已经提到过,WPF属性系统可能直接调用SetValue()方法而跳过我们定义的验证代码。
作为代替,WPF提供了两种方法来防止产生非法值:
1.ValidateValueCallback 此函数可以接受或者拒绝新值。通常被用来捕获违反属性约束的明显错误。在DependencyProperty.Register()方法中有一个参数提供了该回调函数。
2.CoerceValueCallback 此函数可以将新值修改为更容易被接受的值。通常用来处理相同对象设置的依赖属性值相冲突的问题。这些值本身都是合法的,但是它们本身不相 容。此方法在FrameworkPropertyMetadata对象的构造函数中作为一个参数。
调用顺序:
在初始化时,调用ValidateValueCallback 。
在值被修改时,先调用ValidateValueCallback,然后调用CoerceValueCallback,当两者都正常时,再调用响应函数PropertyChangedCallback。
如果有父类存在,会先调用父类的ValidateValueCallback,再调用子类的ValidateValueCallback,但是强制回调CoerceValueCallback只有子类的被调用。
7.最后的例子
为了帮助理解记忆,我写了一个小例子,代码比较少,直接贴出来了
public class test:DependencyObject { public int MyProperty { get { return (int)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(int), typeof(test), new UIPropertyMetadata(0, PropertyChanged, CoerceValue), ValidateValue); static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MessageBox.Show(String.Format("PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue)); } //返回强制转换后的值 static object CoerceValue(DependencyObject dobj, object newValue) { MessageBox.Show(String.Format("CoerceValue - {0}", newValue)); return newValue; } static bool ValidateValue(object obj) { MessageBox.Show(String.Format("ValidateValue - {0}", obj)); return true; } }在主函数中实例一个对象
public MainWindow() { InitializeComponent(); test a = new test(); a.MyProperty = 10; }运行结果顺序如下:
ValidateValue - 0
---------------------------
ValidateValue - 0
---------------------------
ValidateValue - 10
---------------------------
CoerceValue - 10
---------------------------
PropertyChanged - 属性:MyProperty 新值:10 旧值:0
.
可以看到有两次的ValidateValue,应该是new test()时就调用了一次ValidateValue,然后当属性值发生改变时又调用了一次ValidateValue。符合6小节中提到的调用顺序。
- WPF 依赖属性 DependencyProperty
- 一站式WPF--依赖属性(DependencyProperty)
- 一站式WPF--依赖属性(DependencyProperty)一
- 一站式WPF--依赖属性(DependencyProperty)二
- 一站式WPF--依赖属性(DependencyProperty)一
- 一站式WPF--依赖属性(DependencyProperty)二
- Silverlight&WPF依赖属性DependencyProperty讲解
- 一站式WPF--依赖属性(DependencyProperty)一
- 依赖属性(DependencyProperty)
- 依赖属性(DependencyProperty)
- DependencyProperty 依赖属性
- WPF 依赖属性,用户控件依赖属性(DependencyProperty 依赖属性、GetValue() SetValue() CLR属性包装器、SetBinding 数据绑定)
- WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性
- WPF--DependencyProperty
- WPF DependencyProperty
- wpf DependencyProperty
- 坚持学习WF(4):活动(Activity)和依赖属性(DependencyProperty)
- WPF之依赖属性
- MySQL修改root密码的多种方法
- listview的用法
- 做为技术人员为什么要写博客
- 【转载】计算机视觉领域的一些牛人博客,超有实力的研究机构等的网站链接
- apt软件包管理
- WPF 依赖属性 DependencyProperty
- 缓冲文件命名规则
- freemarker基础
- Leetcode: Set Matrix Zeroes
- UVA 11401 - Triangle Counting
- Linux下的文本dos格式转Unix格式,去除^M符号
- 工作感悟与期望的破灭
- VML应用-利用ECOTree绘制树形结构图
- 数据库连接