依赖项属性虽然在使用上和CLR属性同样,可是它是WPF特有的,不一样于CLR属性。只是封装为咱们经常使用CLR的属性,在语法使用上和CLR属性同样。WPF中一些功能:动画,属性绑定,样式等都是以依赖项属性为基础的。WPF中元素的属性大部分都是依赖项属性。html
依赖项属性和CLR属性最主要的区别是:CLR属性是经过一个私有的字段来读取。而依赖项属性则是经过继承在DependencyObject
的GetValue()
和SetValue()
方法动态的读取属性值。app
就是说当设置一个依赖项属性值时,并非直接给一个对象的字段赋值,而是在一个DependencyObject
对象的字典中设置键值对。Key
值为属性的名称,Value
值为你要赋值的值。函数
为何使用依赖项属性:字体
减小内存
当UI控件的90%以上的属性一般停留在初始值时,为每一个属性存储字段会是一个巨大的消耗。依赖项属性则是只在实例中存储修改的属性,那些默认值只在依赖项属性中存储一次。(如字体属性,并非每一个元素都存储一个字体属性,字体属性只存储一次,其余元素则是继承该字体属性。即:值继承)动画
值继承
当访问依赖项属性时,该属性值将经过使用一个值解析策略来解决:若是没有设置本地值,则依赖属性将导航到逻辑树,直到找到一个值为止。当在根元素上设置FontSize时,它将应用该根元素的全部子元素的全部文本块,除非在子元素中从新设置了FontSize值。.net
更改通知
依赖属性有一个内置的变动通知机制。经过在属性元数据中注册一个回调,当属性值被更改时,就会获得通知。这也是数据绑定所使用的。code
若是但愿本来不支持数据绑定,动画,或其余WPF功能的代码实现这些功能时,就要建立依赖项属性。htm
声明一个DependencyProperty
类型的字段,表示依赖项属性的对象。该属性的值应该始终保持可用,同时为了保证在多个类之间共享该属性信息,必须将DependencyProperty
对象定义为与其类关联的静态字段,WPF为了确保在建立DependencyProperty
对象后不能修改该对象,因此全部的DependencyProperty
成员都是只读的。
(如:Margin属性,全部的类都共享该属性,因此该属性必须是与类自己关联。)对象
//声明一个当前时间的依赖项属性 public static readonly DependencyProperty CurrentTimeProperty;
在使用该属性代码以前要先完成注册(即该属性和被注册的类和数据类型,默认值,及一些事件关联起来)完成,所以要在与其关联的静态构造函数中进行。WPF为了确保DependencyProperty
对象不能被直接实例化,使DependencyProperty
类没有公有的构造函数。只能使用静态方法DependencyPropery.Register()
建立DependencyProperty
实例。这些注册的值必须做为Register()
方法的参数来提供。继承
public class MyClockControl1 { CurrentTimeProperty = DependencyProperty.Register( "CurrentTime", typeof(DateTime), typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now),validateValueCallback); static bool validateValueCallback(object data) { //自定义验证 return true; } }
Register()
注册方法一共有五个参数,其中前三个为必选,后两个为可选参数。
每一个依赖属性都提供了更改通知、值强制和验证的回调。这些回调能够经过FrameworkPropertyMetadata
来实现。
如:
new FrameworkPropertyMetadata( DateTime.Now, OnCurrentTimePropertyChanged, OnCoerceCurrentTimeProperty ),OnValidateCurrentTimeProperty );
值更改回调是一个静态方法,每当该属性值更改时,都会调用这个回调方法。
private static void OnCurrentTimePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { MyClockControl control = source as MyClockControl; DateTime time = (DateTime)e.NewValue; }
在执行属性验证回调前先执行该方法,尝试纠正不合法的属性值。
private static object OnCoerceTimeProperty( DependencyObject sender, object data ) { if ((DateTime)data > DateTime.Now ) { data = DateTime.Now; } return data; }
但依赖项属性的值发生变化时调用该回调方法。该回调方法验证属性值是否合法,若是不合法,返回false,抛出异常。
private static bool OnValidateTimeProperty(object data) { return data is DateTime; }
依赖项属性的包装器,是经过DependencyObject的GetValue()和SetValue()方法来包装。
public DateTime CurrentTime { get { return (DateTime)GetValue(CurrentTimeProperty); } set { SetValue(CurrentTimeProperty, value); } }
完整的代码以下:
// Dependency Property public static readonly DependencyProperty CurrentTimeProperty = DependencyProperty.Register( "CurrentTime", typeof(DateTime), typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now)); // .NET Property wrapper public DateTime CurrentTime { get { return (DateTime)GetValue(CurrentTimeProperty); } set { SetValue(CurrentTimeProperty, value); } } static bool validateValueCallback(object data) { //自定义验证 return true; }
自定义一个依赖项属性,须要挺多的套路,固然这些套路不须要你一个一个代码来敲,在Visual Studio能够输入propdp
再点击两次tab
键,就能够建立依赖项属性模板。 只需修改模板的属性名称和类型便可。
模板代码以下:
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(ownerclass), new PropertyMetadata(0));
附加属性也是一种依赖项属性。与其余依赖项属性不一样的时,其余的依赖项属性是应用到被注册的类上,而附加属性则是应用到其余的类上。
好比:Canvas
的类的Top
和Left
等为附加属性,其余的元素并无该属性,只有Canvas
类有,在使用Canvas.Top
时,若是为每一个元素都定义一个这样的依赖项属性,那么就会大量的重复性代码,且不可维护更改。若是只在Canvas
类型上定义这个依赖项属性,其余的元素只继承使用该属性就好。附加属性就是这样。
附加属性的定义和依赖项属性的定义几乎同样。惟一不一样的是注册是经过调用DependencyProperty.GegisterAttached()
方法来实现,且属性包装器为静态方法。
如:
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached("Top", typeof(double), typeof(Canvas), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.Inherits)); public static void SetTop(UIElement element, double value) { element.SetValue(TopProperty, value); } public static double GetTop(UIElement element) { return (double)element.GetValue(TopProperty); }
至此就能够像使用普通的CLR属性同样使用WPF的依赖项属性。
若有不对,请多多指教!
参考列表: