电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

WPF基础教程之属性系统


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

先决条件

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

依赖项属性和 CLR 属性

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

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

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

依赖项属性支持 CLR 属性

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

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

依赖项属性一个由 DependencyProperty 支持的属性

依赖项属性标识符一个 DependencyProperty 实例在注册依赖项属性时作为返回值获得之后将存储为一个类成员在与 WPF 属性系统交互的许多 API 中此标识符用作一个参数

CLR包装属性的实际 get 和 set 实现这些实现通过在 GetValue 和 SetValue 调用中使用依赖项属性标识符来合并此标识符从而使用 WPF 属性系统为属性提供支持

下面的示例定义 IsSpinning 依赖项属性并说明 DependencyProperty 标识符与它所支持的属性之间的关系

)thisstylewidth=; border= twffan=done>

属性以及支持它的 DependencyProperty 字段的命名约定非常重要

字段总是与属性同名但其后面追加了 Property 后缀

设置属性值

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

在 XAML 中设置属性值

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

在代码中设置属性

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

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

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

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

资源

数据绑定

样式

动画

元数据重写

属性值继承

WPF 设计器集成

资源

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

说明

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

数据绑定

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

说明

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

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

样式

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

动画

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

元数据重写

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

属性值继承

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

说明

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

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

WPF 设计器集成

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

依赖项属性值优先级

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

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

说明

SDK 文档在讨论依赖项属性时有时会使用本地值

本地设置的值等术语本地设置的值是指在代码中直接为对象实例设置的属性 (Property) 值或者在 XAML 中设置为元素属性 (Attribute) 的属性 (Property) 值

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

alt= src=http://imgeducitycn/img_///jpg width= onload=javascript:if(thiswidth>)thisstylewidth=; border= twffan=done>

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

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

说明

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

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

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

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

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

上一篇:Page

下一篇:完美iframe自适应宽度和高度