WPF--属性系统

Posted X·3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF--属性系统相关的知识,希望对你有一定的参考价值。

WPF--属性系统

Windows Presentation Foundation(WPF)提供了一组服务,这些服务可用于扩展公共语言运行库(CLR)属性的功能。这些服务通常统称为WPF属性系统。由 WPF 属性系统支持的属性称为依赖项属性。本概述介绍WPF属性系统以及依赖项属性的功能,这包括如何在可扩展应用程序标记语言(XAML)中和代码中使用现有的依赖项属性。本概述还介绍了依赖项属性所特有的方面(如依赖项属性元数据),并说明了如何在自定义类中创建自己的依赖项属性。

先决条件

本主题假设您在CLR和面向对象的编程方面有一些基础知识。若要采用本主题中的示例,还应当了解XAML并知道如何编写WPF应用程序。

依赖项属性和CLR属性

在WPF中,属性通常公开为公共语言运行库(CLR)属性。在基本级别,您可以在根本不知道这些属性实现为依赖项属性的情况下直接与它们交互。但是,您应当熟悉WPF属性系统的部分或全部功能,才能利用这些功能。

依赖项属性的用途在于提供一种方法来基于其他输入的值计算属性值。这些其他输入可以包括系统属性(如主题和用户首选项)、实时属性确定机制(如数据绑定和动画/演示图板)、重用模板(如资源和样式)或者通过与元素树中其他元素的父子关系来公开的值。另外,可以通过实现依赖项属性来提供独立验证、默认值、监视其他属性的更改的回调以及可以基于可能的运行时信息来强制指定属性值的系统。派生类还可以通过重写依赖项属性元数据(而不是重写现有属性的实际实现或者创建新属性)来更改现有属性的某些具体特征。

在SDK参考中,可以根据某个属性的托管引用页上是否存在“依赖项属性信息”部分来确定该属性是否为依赖项属性。“依赖项属性信息”部分包括一个指向该依赖项属性的DependencyProperty标识符字段的链接,还包括一个为该属性设置的元数据选项的列表、每个类的重写信息以及其他详细信息。

依赖项属性支持CLR属性

依赖项属性和WPF属性系统通过提供一个支持属性的类型来扩展属性功能,这是使用私有字段支持该属性的标准模式的替代实现方法。该类型的名称是DependencyProperty。定义WPF属性系统的另一个重要类型是DependencyObject。DependencyObject定义可以注册和拥有依赖项属性的基类。

下面汇集了在本软件开发工具包(SDK)文档中,在讨论依赖项属性时所使用的术语:

  1. 依赖项属性:一个由DependencyProperty支持的属性。
  2. 依赖项属性标识符:一个DependencyProperty实例,在注册依赖项属性时作为返回值获得,之后将存储为一个类成员。在与WPF属性系统交互的许多API中,此标识符用作一个参数。
  3. CLR“包装”:属性的实际get和set实现。这些实现通过在GetValue和SetValue调用中使用依赖项属性标识符来合并此标识符,从而使用WPF属性系统为属性提供支持。

下面的示例定义IsSpinning依赖项属性,并说明DependencyProperty标识符与它所支持的属性之间的关系。属性以及支持它的DependencyProperty字段的命名约定非常重要。字段总是与属性同名,但其后面追加了Property后缀。

设置属性值

可以在代码或XAML中设置属性。

在 XAML 中设置属性值

下面的 XAML 示例将按钮的背景色指定为红色。该示例演示了这样一种情况:在所生成的代码中,XAML加载器将XAML属性的简单字符串值的类型转换为WPF类型(一种Color,通过SolidColorBrush)。

XAML支持各种设置属性的语法格式。要对特定的属性使用哪种语法取决于该属性所使用的值类型以及其他因素(例如,是否存在类型转换器)。

作为非属性语法的示例,下面的XAML示例显示了另一种按钮背景。这一次不是设置简单的纯色,而是将背景设置为图像,用一个元素表示该图像并将该图像的源指定为嵌套元素的属性。这是属性元素语法的示例。

在代码中设置属性

在代码中设置依赖项属性值通常只是调用由CLR“包装”公开的set实现。

获取属性值实质上也是在调用get“包装”实现:

您还可以直接调用属性系统API GetValue和SetValue。如果您使用的是现有属性,则上述操作通常不是必需的(使用包装会更方便,并能够更好地向开发人员工具公开属性)。但是在某些情况下适合直接调用API。

还可以在XAML中设置属性,然后通过代码隐藏在代码中访问这些属性。

由依赖项属性提供的属性功能

依赖项属性提供用来扩展属性功能的功能,这与字段支持的属性相反。每个这样的功能通常都表示或支持整套WPF功能中的特定功能:

  1. 资源
  2. 数据绑定
  3. 样式
  4. 动画
  5. 元数据重写
  6. 属性值继承
  7. WPF 设计器集成

资源

依赖项属性值可以通过引用资源来设置。资源通常指定为页面根元素或应用程序的子元素,通过这些位置可以最方便地访问资源。下面的示例演示如何定义SolidColorBrush资源。

在定义了某个资源之后,可以引用该资源并使用它来提供属性值:

这个特定的资源称为DynamicResource标记扩展(在XAML中,可以使用静态或动态资源引用)。若要使用动态资源引用,必须设置为依赖项属性,因此它是由WPF属性系统明确启用的动态资源引用用法。

说明:

资源被视为本地值,这意味着,如果您设置另一个本地值,该资源引用将被消除。

数据绑定

依赖项属性可以通过数据绑定来引用值。数据绑定通过特定的标记扩展语法(在XAML中)或Binding对象(在代码中)来工作。使用数据绑定,最终属性值的确定将延迟到运行时,在运行时,将从数据源获取属性值。

下面的示例在XAML中使用一个绑定,为Button设置Content属性。该绑定使用一个继承的数据上下文和一个XmlDataProvider数据源(未显示出来)。绑定本身通过数据源中的XPath指定所需的源属性。

绑定被视为本地值,这意味着,如果您设置另一个本地值,该绑定将被消除。

依赖项属性或DependencyObject类本身并不支持INotifyPropertyChanged,以便为数据绑定操作生成有关DependencyObject源属性值变化的通知。

样式

样式和模板是使用依赖项属性的两个主要激发方案。在设置定义应用程序用户界面(UI)的属性时,样式尤其有用。样式在XAML中通常定义为资源。样式与属性系统交互,因为它们通常包含特定属性的“setter”,以及基于另一个属性的实时值更改属性值的“trigger”。

下面的示例创建一个非常简单的样式(该样式将在Resources字典中定义,未显示出来),然后将该样式直接应用于Button的Style属性。样式中的setter将带样式的Button的Background属性设置为green。

动画

可以对依赖项属性进行动画处理。在应用和运行动画时,经过动画处理的值的操作优先级将高于该属性以其他方式具有的任何值(如本地值)。

下面的示例对Button属性的Background进行动画处理(在技术上Background是通过使用属性元素语法将空白SolidColorBrush指定为Background来进行动画处理的,之后,该SolidColorBrush的Color属性就是直接进行动画处理的属性)。

元数据重写

在从最初注册依赖项属性的类派生时,可以通过重写依赖项属性的元数据来更改该属性的某些行为。对元数据的重写依赖于DependencyProperty标识符。重写元数据不需要重新实现属性。元数据的变化是由属性系统在本机处理的;对于所有从基类继承的属性,每个类都有可能基于每个类型保留元数据。

下面的示例重写依赖项属性DefaultStyleKey的元数据。重写这个特定的依赖项属性的元数据是某个实现模式的一部分,该模式创建可以使用主题中的默认样式的控件。

属性值继承

元素可以从其在树中的父级继承依赖项属性的值。

说明:

属性值继承行为并未针对所有的依赖项属性在全局启用,因为继承的计算时间确实会对性能产生一定的影响。属性值继承通常只有在特定方案指出适合使用属性值继承时才对属性启用。可以通过在SDK参考中查看某个依赖项属性的“依赖项属性信息”部分,来确定该依赖项属性是否继承属性值。

下面的示例演示一个绑定,并设置指定绑定(在前面的绑定示例中未显示出来)的源的DataContext属性。DataContext属性的值继承,因此子元素中的任何后续绑定都不必遵守在父级StackPanel元素中指定为DataContext的源。

WPF 设计器集成

如果自定义控件具有实现为依赖项属性的属性,则它将收到相应的Visual Studio Windows Presentation Foundation (WPF)设计器支持。一个示例就是能够在“属性”窗口中编辑直接依赖项属性和附加依赖项属性。

依赖项属性值优先级

当您获取依赖项属性的值时,可能会获得通过其他参与 WPF 属性系统且基于属性的任一输入而在该属性上设置的值。由于存在依赖项属性值优先级,使得属性获取值的方式的各种方案得以按可预测的方式交互。

请看下面的示例。该示例包括一个应用于所有按钮及其Background属性的样式,但是之后还指定了一个具有在本地设置的Background值的按钮。

说明:

SDK文档在讨论依赖项属性时有时会使用“本地值”或“本地设置的值”等术语。本地设置的值是指在代码中直接为对象实例设置的属性(Property)值,或者在XAML中设置为元素属性(Attribute)的属性(Property)值。

实际上,对于第一个按钮,该属性设置了两次,但是仅应用了一个值,即,具有最高优先级的值。本地设置的值具有最高优先级(对于正在运行的动画除外,但是在本示例中没有应用动画),因此,对于第一个按钮的背景将使用本地设置的值,而不使用样式setter值。第二个按钮没有本地值(而且没有其他比样式setter优先级更高的值),因此该按钮中的背景将来自样式setter。

为什么存在依赖项属性优先级?

通常,您不会希望总是应用样式,而且不希望样式遮盖单个元素的哪怕一个本地设置值(否则,通常将很难使用样式或元素)。因此,来自样式的值的操作优先级将低于本地设置的值。

说明:

在WPF元素定义了许多非依赖项属性的属性。一般说来,只有在需要支持至少一个由属性系统启用的方案(数据绑定、样式、动画、默认值支持、继承、附加属性或失效)时,才将属性实现为依赖项属性。

了解有关依赖项属性的更多信息

附加属性是一种类型的属性,它支持XAML中的专用语法。附加属性通常与公共语言运行库(CLR)属性不具有1:1对应关系,而且不一定是依赖项属性。附加属性的典型用途是使子元素可以向其父元素报告属性值,即使父元素和子元素的类成员列表中均没有该属性也是如此。一个主要方案是,使子元素可以将其在 UI 中的表示方式通知给父级。

组件开发人员或应用程序开发人员可能希望创建自己的依赖项属性,以便实现数据绑定或样式支持之类的功能,或者实现对失效和强制指定值的支持。

通常,依赖项属性应当被视为公共属性,这些公共属性可以由任何具有实例访问权限的调用方访问,或至少可被这样的调用方发现

以上是关于WPF--属性系统的主要内容,如果未能解决你的问题,请参考以下文章

WPF入门教程系列十四——依赖属性

WPF学习第十二章 属性验证

WPF学习第十二章 属性验证

WPF--样式设置

WPF--属性系统

WPF--属性系统