Chinaunix首页 | 论坛 | 博客
  • 博客访问: 370181
  • 博文数量: 71
  • 博客积分: 4691
  • 博客等级: 上校
  • 技术积分: 935
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-14 15:14
个人简介

who am i ... i'm back.

文章分类

全部博文(71)

文章存档

2014年(4)

2011年(1)

2010年(22)

2009年(17)

2008年(27)

我的朋友

分类:

2009-04-01 19:35:29

3.2  依赖属性

WPF引入了一个新的属性类型叫作依赖属性,整个WPF平台中都会使用到它,用来实现样式化、自动数据绑定、动画等。你可能在怀疑论 (skepticism)中第一次遇到这个概念,它使得.NET类型图变得很复杂,其中有简单的字段、属性、方法和事件。但是在你理解依赖属性解决的问题 之后,很有可能会把它们作为一种“不错的添加剂”。

依赖属性在任何时刻都是依靠多个提供程序来判断它的值的。这些提供程序可以是一段一直在改变值的动画,或者一个父元素的属性值从上慢慢传递给子元素等。依赖属性的最大特征是其内建的传递变更通知(change notification)的能力。

添加这样的智能给属性,其动力在于能够声明标记中直接启用富功能(rich functionality)。WPF友好声明设计的关键在于它使用了很多属性。例如,Button控件有96个公共属性!属性可以方便地在XAML中设 置(直接或者通过设计工具)而不用程序代码。但是如果依赖属性没有额外的垂直传递,在不写额外代码的情况下,很难在设置属性这样简单的动作中获得想要的结 果。

在本节中,我们将简要地看一下依赖属性的实现,让讨论更加具体。然后我们再深入分析依赖属性在普通.NET属性上赋值的下面一些方式:

·变更通知

·属性值继承

·对多提供程序的支持

理解大多数依赖属性的细微差别,通常只是对于自定义控件设计者来说是重要的。然而,即使是WPF的普通用户,最终也需要了解依赖属性是什么以及它们 如何工作。例如,你只能为依赖属性添加风格和动画效果。在使用WPF工作一段时间之后,你会发现你其实希望所有的属性都是依赖属性!

3.2.1  依赖属性的实现

实际上,依赖属性仅仅是普通的.NET属性,只不过它已融入到了WPF架构中。它完全是由WPF API实现的,没有一种.NET语言(除了XAML以外)天生就能理解依赖属性。

代码清单3-3展示了一个Button如何有效地实现一个叫作IsDefault的依赖属性。

代码清单3-3  一个标准的依赖属性实现

IsDefaultProperty静态成员是真正的依赖属性,类型为System.Windows.DependencyProperty。按规 则,所有的DependencyProperty成员都必须是public、static,并且有一个Property作为后缀。依赖属性通常是通过调用 DependencyProperty.Register静态方法创建的,这样的方法需要一个名称(IsDefault)、一个属性类型(bool)以及 拥有这个属性的类(Button类)。通过不同的Register方法重载,你可以传入metadata(元数据)来告诉WPF如何处理该属性、如何处理 属性值改变的回调、如何处理强制值转换,以及如何验证值。Button会在它的静态构造函数中调用Register的重载,给依赖属性一个默认值 false,并为变更通知添加一个委托。

最后,那个叫作IsDefault的传统.NET属性会调用继承自System.Windows.Dependency- Object的GetValue和SetValue方法来实现自己的访问器,System.Windows.DependencyObject是底层基 类,这是拥有依赖属性的类必须继承的。GetValue返回最后一次由SetValue设置的值,如果SetValue从未被调用过,那么就是该属性注册 时的默认值。IsDefault .NET属性(有时叫作此上下文中的属性包装器)并不是必需的,Button的使用者可能会直接调用GetValue/ SetValue方法,因为它们是公开的。但是.NET属性会让以编程方式读写属性变得更加自然,它还允许通过XAML设置属性。

注意 在运行时,绕过了.NET属性包装器在XAML中设置依赖属性。

虽然XAML编译器在编译时是依靠该属性包装器的,但在运行时WPF是直接调用GetValue和 SetValue的!因此,为了让使用XAML设置属性与使用过程式代码设置属性保持一致,在属性包装器中除了GetValue/SetValue调用以 外,不应该包含任何其他逻辑,这是至关重要的。如果需要添加自定义逻辑,应该在注册的回调函数中添加。所有WPF的内建属性包装器都应遵守这个规则,因此 这个警告是针对那些打算写带有依赖属性的自定义类的人的。

从表面上看,代码清单3-3像是一种冗长的呈现简单布尔属性的方式。然而,因为GetValue和SetValue内部使用了高效的稀疏存储系统, 而IsDefaultProperty是一个静态成员(而不是一个实例成员),与典型的.NET属性相比,依赖属性的实现节省了保存每个实例所需要的内 存。如果WPF控件的所有属性都是实例成员的包装器(与大部分.NET属性一样),由于所有的本地数据都会被添加到每个实例中,这样将会消耗大量的内存。 每个Button有96个成员,每个Label有89个成员……,它们消耗的内存增长起来会很快!实际上,Button的96个属性中有78个是依赖属 性,而Label的89个属性中的71个是依赖属性。

然而,依赖属性的好处远远不止内存使用这一项。它把相当一部分代码集中起来,并做标准化处理,这部分代码原本是要由属性实现者自己来写的,用来检查 线程访问、请求容器元素重新呈现等。例如,当属性的值改变时(如Button的Background属性),如果它要求子元素重新呈现,就只要传递一个 FrameworkPropertyMetadataOptions.AffectsRender标志给DependencyProperty. Register的一个重载。这一实现也列出了之前提到的3个特征,现在我们一个一个来讲解,首先是变更通知。

阅读(1617) | 评论(0) | 转发(0) |
0

上一篇:依赖属性

下一篇:WCF BINDING

给主人留下些什么吧!~~