依懒属性是WPF推出的概念,使用它的好处很多,这一点在Silverlight里也得到了继承,由于这个概念比较抽象,它不同于.NET中一般的属性类型,所以我个人整理了一些关于依赖属性的文章希望对大家有用。
依赖属性(Dependency Properties) 通过该方法的不同重载,我们可以有选择地传递处理自定义属性元数据,也可以编写那些用于处理属性值变更、强制转换(coerce)和验证(validate)的回调方法。Button在其静态构造方法中调用了Register方法的一种重载,并向其提供了依赖属性的默认值(false),并且为处理变更通知(change notification)附加了一个委托。 变更通知 属性值的继承 属性值继承(简称属性继承)与传统的面向对象继承不同,它是指属性值可以沿着元素树向下传递的过程。 例:在Window元素上设置属性 <Window x:Class="Test.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF揭秘" SizeToContent="WidthAndHeight" FontSize="30" FontStyle="Italic" Background="OrangeRed"> <StackPanel> <Label FontWeight="Bold" FontSize="20" Foreground="White"> WPF揭秘(版本3.0) </Label> <Label>(C)2006 SAMS 出版集团</Label> <Label>已安装的章节:</Label> <ListBox> <ListBoxItem>第一章</ListBoxItem> <ListBoxItem>第二章</ListBoxItem> </ListBox> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button MinWidth="75" Margin="10">Help</Button> <Button MinWidth="75" Margin="10">OK</Button> </StackPanel> <StatusBar>您已经注册了本产品。</StatusBar> </StackPanel> </Window> 下图展示了以显式方式设置Window元素的FontSize和FontStyle依赖属性后,整个窗体的变化情况。 为这两个属性设置的值将会沿着元素树向下传递,并被相应的子元素继承(即将子元素的对应属性也被设定为这个值)。上例中,Button、Label和ListBoxItem都受到了影响,但由于第一个Label显式设置了FontSize,从而其字体大小未受影响。值得注意的是,StatusBar中的文本并没有受到这两个值的影响,尽管它与其它控件相同,也包含这两个属性。由于以下两种原因,属性值的继承显得有些微妙: (1)并不是所有的依赖属性都参与属性值的继承(依赖属性可以通过向DependencyProperty.Register传递FrameworkPropertyMatadataOptions.Inherits来选择是否参与继承) (2)可能存在更高优先级的属性设定源(稍后解释) StatusBar显示的结果由第二种原因导致的。一些如StatusBar、Menu和Tooltip控件的内部将它们的字体属性设定为匹配当前系统的设置。这种结果有些令人迷惑,因为这样的控件阻止了继承属性值沿着元素树继续传递。例如,当我们在StatusBar中加入一个Button作为其逻辑子元素,那么Button的FontSize和FontStyle都将保持默认值,这与处于StatusBar之外的那些Button不同。 属性值继承本来是用来操作元素树的,但是它也可以用于在其它情境。例如,属性值可以传递到某个XML意义上的子元素,而这个子元素并非逻辑树或视觉树的子元素。这些伪子元素可以是某个元素的触发器,也可是任意属性值,只要它是一个从Freezable派生的对象就可以。(暂不明) 对多种提供器的支持
"3">ShirtTypes newShirtType = (d as Shirt).ShirtType; |
依赖属性(Dependency Property) .NET Framework 3.0引入了一个新的属性类型叫依赖属性, WPF,WF都在使用依赖属性用来实现样式化,数据绑定等.我们更多的使用依赖属性是为了让父元素的属性值在逻辑树上慢慢的传递到其子元素中,从而可以在整个可是父元素的逻辑子元素中共享属性值.WF就是依靠依赖属性来在工作流中的各Activity间传递属性值的. 所以,依赖属性内建的传递变更通知的能力是其最大特征. 如果你想让属性在一个包含内容子控件树的整个逻辑控件树中都有效并共享值时,你仅仅只需要将这个属性声明为依赖属性即可, WPF会通过内建的架构来支持属性的共享. 而在工作流中我们经常需要用到依赖属性,它保证了在一个工作流实例中,多个组件共享了同一个值. 幸运的是在WPF中大部分空间的属性都是依赖属性,这让我们应用时非常方便,而你并不需要着后边发生了什么。 依赖属性的实现 依赖属性其实也是普通的.NET属性,只是通过DependencyProperty.Register方法将普通的.NET属性注册为依赖属性。在依赖属性的声明中,其实对应的普通.NET属性并不是必需的,因为其内部的GetValue和SetValue方法是公开的,依赖属性的使用者可以通过调用GetValue/SetValue而放弃对普通.NET属性的依赖。但建立在普通.NET熟悉之上更符合我们通常的做法,而且这样有利于在XAML中设置属性。 下面的代码展示了定义依赖属性的通常做法:
在上面的示例代码中是标准的实现依赖属性定义的方法,这里需要注意的是依赖属性始终是定义在普通.NET属性之上的用Register静态方法注册的特殊属性,即便这里的.NET属性(如IsDefault属性)不是必需的。另一个需要注意的地方是,通过声明依赖属性,我们多了一个控制属性改变时的回调方法(即便这同样可以通过声明委托和事件来定义,但这里我们什么都没做,为什么不用呢?),这样的好处是我们可以在属性改变的时候做些我们想做的事情,而我们却省去了手动声明事件的任务。其实回调函数的存在是为了让我们保证在属性包装器中(IsDefault属性)仅仅使用标准的GetValue/SetValue而不用任何其他逻辑,转而将自定义逻辑写入回调函数--这样做是为了遵循WPF的统一设计原则,让XAML 设置属性与使用过程式代码设置属性保持一致。 触发器 依赖属性的实现让我们可以在一个局部范围内保持属性值的共享,这样的好处是对于内存的节约,因为GetValue/SetValue内部使用了高效的稀疏存储系统. 前边提到过,依赖属性的一大特征是变更通知,意思就是当某些依赖属性的只改变了,WPF就会更具属性的元数据触发一系列动作. WPF中有三种方式来实现这样的变更通知: 属性触发器: 在属性发生改变时执行自定义动作,而不用改任何过程代码。 数据触发器: 当普通.NET属性的值改变时调用自定义动作。 事件触发器: 当路由事件被触发时调用自定义动作。 属性触发器(Trigger) 当某个属性有一个特定的值时,属性触发器会执行一个Setter的集合来设置相关对象的属性,而当属性失去这个值的时候,属性触发器会撤消该Setter集合. 这样的好处是大大简化了我们用声明事件的办法来处理满足一定条件时的逻辑,我们在XAML中就可以完成相应的简单逻辑(如果复杂还是需要过程式代码)。
对于属性触发器的应用我们更多的还可以通过自定义验证规则来实现对样式和Tooltip的自动设置。 数据触发器(Data Trigger) 数据触发器与属性触发器几乎一样,只是数据触发器可以由任何.NET属性触发,而不仅仅是依赖属性.为了使用数据触发器,可向Triggers集合中添加DataTrigger对象然后指定属性/值对.同时可以用Binding来指定相关属性而不仅仅是属性名. 以下示例通过binding指定当自己的值为disabled的时候将自己禁用. 注意:Text属性不是依赖属性.
事件触发器(Event Trigger) 当一个已选择的事件产生时事件触发器会被激活.这个事件由触发器的RouteEvent属性指定,他在Action集合中包含一个或多个动作(从抽象类TriggerAction继承来的对象). 下边的示例展示了在Button的Click事件被触发时执行DoubleAnimation动作.
属性值继承 附加属性(Attached Property) 附加属性也属于XAML为了扩展其能力的一种,它提供了让用户在父属性里设置自己没有的子属性值的能力。而在应用附加属性时,通常它也可以体现WPF中属性传递的优点:例如,当你给一个Panel中的某类元素设置了附加属性,那么在不显式声明相关属性值(重写)的情况下,此类元素共同从父元素得到这个值。 作为附加属性,之所以说是扩展了XAML的应用是因为它提供了通过父元素来设置子元素并在其可视树范围内默认共享的能力。那么我们可以通过给Panel来设置TextElement.FontSize属性来让所有在这个Panel下的拥有TextElement.FontSize相关属性的控件自动拥有这个值,而不需要我们挨个对所有此类空间设置。例如:
在上述的例子中,由于在StackPanel中设置了TextElement.FontSize,所以在它的内部的可视控件自动有用这个属性:TextBlock,Button都会以FontSize=10来显示。 |