加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 程序设计 > 正文

依赖属性详解

发布时间:2020-05-23 18:48:44 所属栏目:程序设计 来源:互联网
导读:简介: 当你开始用WPF编程的时候,很快就会碰到“依赖属性 ”。它们和一般的.Net属性看起来很相似,但简单概念之后则是更复杂和更强大。 主要的区别在于:平常的.NET属性的值直接读取 于类的一个私有属性,而依赖属性的值则是通过调用继承自DependencyObject的

简介:

当你开始用WPF编程的时候,很快就会碰到“依赖属性 ”。它们和一般的.Net属性看起来很相似,但简单概念之后则是更复杂和更强大。

主要的区别在于:平常的.NET属性的值直接读取 于类的一个私有属性,而依赖属性的值则是通过调用继承自DependencyObject的GetValue()方法动态赋值 的。

当你给一个依赖属性赋值时,它不是存储在对象的字段 中,而是在存储在基类DependencyObject提供的一个键-值配对的字典 中。一条记录中的键(Key)就是该属性的名称,而值(Value)则是想要设置的值。

依赖属性的优点:

  • 节约内存的使用

在你认为超过90%的用户界面控件的属性通常留其初始值时,为每一个属性存储一个字段将是对内存的巨大的浪费。依赖属性解决了仅仅存储改变了属性的问题。默认值在依赖属性中只存储一次。

  • 值继承

当你访问一个依赖属性时要使用一个值解决策略。如果当前没有值需要设置,则依赖属性会遍历整个逻辑树直至它找到一个值。当你在根元素中设置字体大小时,它会应用于所有文本块,除非你重写这个值。

  • 修改通知

依赖属性有一个内嵌的修改通知机制。当属性的值被改变后,通过在属性元数据注册一个的回调函数就能得到修改的通知。同样也可以用在数据绑定中。

值访问策略

每次访问一个依赖属性,它内部会按照下列的顺序由高到底处理该值。它首先确认自身的值是否可用,如果不可用,则会触发一个自定义的样式触发器……继续直到它找到一个值。最后默认值经常是可用的。

背后的秘密

每一个WPF控件注册了一系列的依赖属性在静态的DependencyProperty类中。他们由一个键值(对每个类都是唯一的)和包含默认值和回调函数的原数据组成。

所有要使用依赖属性(DependecyProperties)的类型都必须由DependencyObject来驱动。这个基类定义了一个键值字典来存储依赖属性的所有值。记录中的键则是依赖属性主要申明的。

当你通过.Net属性包装器访问依赖属性的时候,它在内部会调用一个方法GetValue(DependencyProperty)来访问值。下图详细的解释了该方法使用的值解决策略。 如果当前值是可用的,那么就直接从字典(Dictionary)里读出该值。如果没有值被设定,它将上升到整个逻辑树,寻找一个可继承的值。如果没有找到可继承的值,它将被设置为在属性原数据中定义好的默认值。下面的序列有点简化,但它显示了主要的思想。

创建依赖属性

创建一个依赖属性,需添加一个DepdencyProperty类型的静态字段,并调用DependencyProperty.Register()来创建一个依赖属性的实例。依赖属性一般需要以…Property结尾。这样符合PWF的命名规范。

为了使依赖属性像一般的.Net属性一样被访问,则需要添加一个属性包装器。该包装器除了通过继承自DependencyObject的GetValue()和SetValue()方法,以DependencyProperty作为键值来设置和读取它的值外不做任何事情。

强调:不要在这些属性中添加任何逻辑,因为它们仅仅当在代码中赋值的时候才被调用。而在XAML中可直接调用SetValue方法设定属性

如果你使用的是Visual Studio,你可以输入propdp在敲两次tab键来自动创建一个依赖属性。

代码
    
    
     
     1
 
     
     //

     
      Dependency Property

     
     
2 public static readonly DependencyProperty CurrentTimeProperty =
3 DependencyProperty.Register( " CurrentTime " , typeof (DateTime),
4 typeof (MyClockControl), new FrameworkPropertyMetadata(DateTime.Now));
5
6 // .NET Property wrapper
7 public DateTime CurrentTime
8 {
9 get { return (DateTime)GetValue(CurrentTimeProperty); }
10 set { SetValue(CurrentTimeProperty,value); }
11 }

每一个依赖属性都提供为修改通知,值的强制转换和验证提供了一些回调函数,这些函数须在依赖属性中注册。

   
   
    
    new

    
     FrameworkPropertyMetadata( DateTime.Now,
OnCurrentTimePropertyChanged,
OnCoerceCurrentTimeProperty ),
OnValidateCurrentTimeProperty );

值的修改回调:

修改回调是一个静态方法,任何时候,只要TimeProperty的值改变了,它都会被调用。新的值会在EventArgs参数传输,此次改变的对象则在source里传输。

代码
    
    
     
     private

     
      

     
     static

     
      

     
     void

     
      OnCurrentTimePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyClockControl control = source as MyClockControl;
DateTime time = (DateTime)e.NewValue;
// Put some update logic here...
}

值的限制回调:

限制制回调函数允许调整一个值,如果出界,将会抛出一个异常。一个好的例子就是在进度条中设置一个最大上限值或者最小下限值。这种情况下我们可以限定值在允许的范围内。下面的例子我们排出了已经过去了的时间。

   
   
    
    private

    
     

    
    static

    
     

    
    object

    
     OnCoerceTimeProperty( DependencyObject sender,

    
    object

    
     data )
{
if ((DateTime)data > DateTime.Now )
{
data = DateTime.Now;
}
return data;
}

值的验证回调:

验证回调用来检验要设置的值是否有效。如果返回无效的(False),则抛出一个ArgmentException的异常。我们例子的要求是数值必须是DataTime的实例.

   
   
    
    private

    
     

    
    static

    
     

    
    bool

    
     OnValidateTimeProperty(

    
    object

    
     data)
{
return data is DateTime;
}

只读的依赖属性:

一些WPF控件的依赖属性是只读的。它们经常用于报告控件的状态, 像IsMouSEOver属性。 为它提供赋值是没有意思的。 或许你会问自己,为什么不使用一般的.Net属性?一个重要的原因就是一般的.Net属性不能设置触发器(Trigger)。 创建一个只读的属性跟创建一个平常的属性一样。仅仅用DependencyProperty.RegisterReadonly()替换了 DependencyProperty()。它将返回一个DependencyPropertyKey。这个键值可以保存在类的私有或者保护的静态只读字 段里。该键值在类的内部提供了一个赋值的入口,便可以像一般属性一样使用了。 紧接着第二件事就是注册一个公开的依赖属性指向DependencyPropertyKey.DependencyProperty。这个属性对外部的访问便是只读的。 代码
     
     
      
      //

      
       Register the private key to set the value

      
      
private static readonly DependencyPropertyKey IsMouSEOverPropertyKey =
DependencyProperty.RegisterReadOnly( " IsMouSEOver " ,
typeof ( bool ), typeof (MyClass),
new FrameworkPropertyMetadata( false ));

// Register the public property to get the value
public static readonly DependencyProperty IsMouSEOverProperty =
IsMouSEOverPropertyKey.DependencyProperty;

// .NET Property wrapper
public int IsMouSEOver
{
get { return ( bool )GetValue(IsMouSEOverProperty); }
private set { SetValue(IsMouSEOverPropertyKey,value); }
}

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读