依赖项属性元数据Dependency Property Metadata

Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF)属性系统包含一个元数据报告系统, 该系统超出了可通过反射或一般公共语言运行时 (CLR) 特征报告的属性的内容。The Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) property system includes a metadata reporting system that goes beyond what can be reported about a property through reflection or general common language runtime (CLR) characteristics. 依赖属性的元数据还可以由定义依赖属性的类来唯一地分配,可以在依赖属性添加到另一个类时进行更改,可以由所有从定义基类继承依赖属性的派生类来明确地重写。Metadata for a dependency property can also be assigned uniquely by the class that defines a dependency property, can be changed when the dependency property is added to a different class, and can be specifically overridden by all derived classes that inherit the dependency property from the defining base class.

系统必备Prerequisites

本主题假定你从 Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) 类的现有依赖属性的使用者角度了解依赖属性,并且已阅读依赖属性概述This topic assumes that you understand dependency properties from the perspective of a consumer of existing dependency properties on Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) classes, and have read the Dependency Properties Overview. 若要理解本主题中的示例,还应当了解 XAMLXAML 并知道如何编写 WPFWPF 应用程序。In order to follow the examples in this topic, you should also understand XAMLXAML and know how to write WPFWPF applications.

依赖属性元数据的使用方式How Dependency Property Metadata is Used

依赖属性的元数据作为一个对象存在,可以通过查询该对象来检查依赖属性的特征。Dependency property metadata exists as an object that can be queried to examine the characteristics of a dependency property. 当属性系统处理任何给定的依赖属性时,也会经常访问这些元数据。This metadata is also accessed frequently by the property system as it processes any given dependency property. 依赖属性的元数据对象可以包含以下类型的信息:The metadata object for a dependency property can contain the following types of information:

  • 依赖属性的默认值(如果通过本地值、样式和继承等信息不能确定依赖属性的其他任何值)。有关在为依赖属性赋值时,默认值如何参与属性系统所使用的优先级的完整讨论,请参阅依赖属性值优先级Default value for the dependency property, if no other value can be determined for the dependency property by local value, style, inheritance, etc. For a thorough discussion of how default values participate in the precedence used by the property system when assigning values for dependency properties, see Dependency Property Value Precedence.

  • 对影响每个所有者类型的强制行为或更改通知行为的回叫实现的引用。References to callback implementations that affect coercion or change-notification behaviors on a per-owner-type basis. 请注意,这些回叫通常是用非公共访问级别定义的,因此,除非实际引用位于允许的访问范围内,否则通常无法从元数据获得这些引用。Note that these callbacks are often defined with a nonpublic access level, so obtaining the actual references from metadata is generally not possible unless the references are within your permitted access scope. 有关依赖属性回叫的详细信息,请参阅依赖属性回调和验证For more information on dependency property callbacks, see Dependency Property Callbacks and Validation.

  • 如果所讨论的依赖属性被视为一个 WPF 框架级别的属性,则元数据中可能包含 WPF 框架级别的依赖属性特征,这些特征报告各种服务(如 WPF 框架级别的布局引擎和属性继承逻辑)的信息和状态。If the dependency property in question is considered to be a WPF framework-level property, the metadata might contain WPF framework-level dependency property characteristics, which report information and state for services such as the WPF framework-level layout engine and property inheritance logic. 有关依赖属性元数据的这一方面的详细信息,请参阅框架属性元数据For more information on this aspect of dependency property metadata, see Framework Property Metadata.

元数据 APIMetadata APIs

报告属性系统使用的大多数元数据信息的类型是PropertyMetadata类。The type that reports most of the metadata information used by the property system is the PropertyMetadata class. 在向属性系统注册依赖属性时,可以选择指定元数据实例,并且可以为以下附加类型再次指定这些实例:将自身作为所有者添加的类型,或者重写它们从基类依赖属性定义继承的元数据的类型。Metadata instances are optionally specified when dependency properties are registered with the property system, and can be specified again for additional types that either add themselves as owners or override metadata they inherit from the base class dependency property definition. (在属性注册未指定元数据的情况下, 将使用PropertyMetadata该类的默认值创建默认值。)PropertyMetadata当调用从DependencyObject实例的依赖项属性获取元数据GetMetadata的各种重载时, 将返回已注册的元数据。(For cases where a property registration does not specify metadata, a default PropertyMetadata is created with default values for that class.)The registered metadata is returned as PropertyMetadata when you call the various GetMetadata overloads that get metadata from a dependency property on a DependencyObject instance.

然后从派生类, 以便为体系结构分部 (如 WPF 框架级类) 提供更具体的元数据。 PropertyMetadataThe PropertyMetadata class is then derived from to provide more specific metadata for architectural divisions such as the WPF framework-level classes. UIPropertyMetadata添加动画报告, 并FrameworkPropertyMetadata提供上一节中提到的 WPF 框架级属性。UIPropertyMetadata adds animation reporting, and FrameworkPropertyMetadata provides the WPF framework-level properties mentioned in the previous section. 当注册依赖属性时, 可以将它们注册到这些PropertyMetadata派生类。When dependency properties are registered, they can be registered with these PropertyMetadata derived classes. 检查元数据时, 可以将基PropertyMetadata类型强制转换为派生类, 以便可以检查更具体的属性。When the metadata is examined, the base PropertyMetadata type can potentially be cast to the derived classes so that you can examine the more specific properties.

备注

FrameworkPropertyMetadata此文档中, 可以指定的属性特征有时被称为 "标志"。The property characteristics that can be specified in FrameworkPropertyMetadata are sometimes referred to in this documentation as "flags". 当你创建新的元数据实例以便在依赖属性注册或元数据重写中使用时, 你可以FrameworkPropertyMetadataOptions使用 flagwise 枚举指定这些值, 然后提供可能连接的枚举值到FrameworkPropertyMetadata构造函数。When you create new metadata instances for use in dependency property registrations or metadata overrides, you specify these values using the flagwise enumeration FrameworkPropertyMetadataOptions and then you supply possibly concatenated values of the enumeration to the FrameworkPropertyMetadata constructor. 但是, 一旦构造后, 这些选项特征在中FrameworkPropertyMetadata作为一系列布尔属性公开, 而不是构造枚举值。However, once constructed, these option characteristics are exposed within a FrameworkPropertyMetadata as a series of Boolean properties rather than the constructing enumeration value. 使用布尔属性,可以检查每个条件,而不必为了获得感兴趣的信息而向按标志枚举值应用掩码。The Boolean properties enable you to check each conditional, rather than requiring you to apply a mask to a flagwise enumeration value to get the information you are interested in. 构造函数使用串联FrameworkPropertyMetadataOptions以便保持构造函数签名的长度合理, 而实际构造的元数据公开了离散属性, 使查询元数据更加直观。The constructor uses the concatenated FrameworkPropertyMetadataOptions in order to keep the length of the constructor signature reasonable, whereas the actual constructed metadata exposes the discrete properties to make querying the metadata more intuitive.

何时重写元数据以及何时派生类When to Override Metadata, When to Derive a Class

WPFWPF 属性系统已经建立了如下功能:在不必完全重新实现依赖属性的情况下,更改依赖属性的某些特征。The WPFWPF property system has established capabilities for changing some characteristics of dependency properties without requiring them to be entirely re-implemented. 这是通过为特定类型上所存在的依赖属性构造不同的属性元数据实例来完成的。This is accomplished by constructing a different instance of property metadata for the dependency property as it exists on a particular type. 请注意,现有的大多数依赖属性都不是虚拟属性,因此,严格地说,只能通过隐藏现有成员来针对继承类“重新实现”依赖属性。Note that most existing dependency properties are not virtual properties, so strictly speaking "re-implementing" them on inherited classes could only be accomplished by shadowing the existing member.

如果尝试对某个类型的依赖属性启用的方案不能通过修改现有依赖属性的特征来完成,则可能有必要创建一个派生类,然后为该派生类声明一个自定义依赖属性。If the scenario you are trying to enable for a dependency property on a type cannot be accomplished by modifying characteristics of existing dependency properties, it might then be necessary to create a derived class, and then to declare a custom dependency property on your derived class. 自定义依赖项属性的行为与WPFWPF api 定义的依赖项属性的行为相同。A custom dependency property behaves identically to dependency properties defined by the WPFWPF APIs. 有关自定义依赖属性的更多详细信息,请参阅自定义依赖属性For more details about custom dependency properties, see Custom Dependency Properties.

不能重写的依赖属性的一个显著特征就是它的值类型。One notable characteristic of a dependency property that you cannot override is its value type. 如果要继承的依赖属性的行为与所需的行为大体相同,但是要求它具有另一种类型,则必须实现一个自定义依赖属性,可能还需要通过类型转换或其他实现机制在自定义类上链接这些属性。If you are inheriting a dependency property that has the approximate behavior you require, but you require a different type for it, you will have to implement a custom dependency property and perhaps link the properties through type conversion or other implementation on your custom class. 此外, 不能替换现有ValidateValueCallback的, 因为此回调存在于注册字段本身中, 而不在其元数据中。Also, you cannot replace an existing ValidateValueCallback, because this callback exists in the registration field itself and not within its metadata.

更改现有元数据的方案Scenarios for Changing Existing Metadata

如果要处理现有依赖属性的元数据,则更改依赖属性元数据的一种常见方案是更改默认值。If you are working with metadata of an existing dependency property, one common scenario for changing dependency property metadata is to change the default value. 更改或添加属性系统回叫是一种更高级的方案。Changing or adding property system callbacks is a more advanced scenario. 如果所实现的派生类的依赖属性之间具有不同的相互关系,则你可能希望这样做。You might want to do this if your implementation of a derived class has different interrelationships between dependency properties. 让编程模型既支持代码又支持声明性用法的条件之一就是,属性必须能够按任何顺序设置。One of the conditionals of having a programming model that supports both code and declarative usage is that properties must enable being set in any order. 因此,需要在没有上下文的情况下实时设置任何依赖属性,而且可以不必知道设置顺序(例如,可能在构造函数中找到的顺序)。Thus any dependent properties need to be set just-in-time without context and cannot rely on knowing a setting order such as might be found in a constructor. 有关属性系统这一方面的详细信息,请参阅依赖属性回调和验证For more information on this aspect of the property system, see Dependency Property Callbacks and Validation. 请注意,验证回叫不是元数据的一部分,而是依赖属性标识符的一部分。Note that validation callbacks are not part of the metadata; they are part of the dependency property identifier. 因此,不能通过重写元数据来更改验证回叫。Therefore, validation callbacks cannot be changed by overriding the metadata.

在某些情况下,可能还希望在现有的依赖属性上改变 WPF 框架级别的属性元数据选项。In some cases you might also want to alter the WPF framework-level property metadata options on existing dependency properties. 这些选项将有关 WPF 框架级别属性的某些已知条件传递到其他 WPF 框架级别的进程,例如布局系统。These options communicate certain known conditionals about WPF framework-level properties to other WPF framework-level processes such as the layout system. 通常, 仅当注册新的依赖属性时才会设置选项, 但也可以将 WPF 框架级别的属性元数据作为OverrideMetadataAddOwner调用的一部分进行更改。Setting the options is generally done only when registering a new dependency property, but it is also possible to change the WPF framework-level property metadata as part of a OverrideMetadata or AddOwner call. 有关要使用的特定值以及详细信息,请参阅框架属性元数据For the specific values to use and more information, see Framework Property Metadata. 有关应当如何为新注册的依赖属性设置这些选项的详细信息,请参阅自定义依赖属性For more information that is pertinent to how these options should be set for a newly registered dependency property, see Custom Dependency Properties.

重写元数据Overriding Metadata

重写元数据的主要目的在于,使你有机会更改各种派生自元数据的行为,这些行为应用于类型上存在的依赖属性。The purpose of overriding metadata is primarily so that you have the opportunity to change the various metadata-derived behaviors that are applied to the dependency property as it exists on your type. 元数据一节中更详细地介绍了重写元数据的原因。The reasons for this are explained in more detail in the Metadata section. 有关详细信息(包括一些代码示例),请参阅重写依赖属性的元数据For more information including some code examples, see Override Metadata for a Dependency Property.

可以在注册调用 (Register) 期间为依赖属性提供属性元数据。Property metadata can be supplied for a dependency property during the registration call (Register). 但是,在许多情况下,当类继承该依赖属性时,你可能希望为该类提供特定于类型的元数据。However, in many cases, you might want to provide type-specific metadata for your class when it inherits that dependency property. 可以通过调用OverrideMetadata方法来执行此操作。You can do this by calling the OverrideMetadata method. 对于来自WPFWPF api 的示例FrameworkElement , 类是第一次注册Focusable依赖属性的类型。For an example from the WPFWPF APIs, the FrameworkElement class is the type that first registers the Focusable dependency property. 但是, Control类会重写依赖属性的元数据, 以提供其自己的初始默认值false , true将其从更改为, 否则会Focusable重新使用原始实现。But the Control class overrides metadata for the dependency property to provide its own initial default value, changing it from false to true, and otherwise re-uses the original Focusable implementation.

当你重写元数据时,系统会合并或替换不同的元数据特征。When you override metadata, the different metadata characteristics are either merged or replaced.

此行为由Merge实现, 并且可在派生的元数据类上重写。This behavior is implemented by Merge, and can be overridden on derived metadata classes.

重写附加属性元数据Overriding Attached Property Metadata

WPFWPF 中,附加属性作为依赖属性来实现。In WPFWPF, attached properties are implemented as dependency properties. 这意味着它们还具有能够由个别类重写的属性元数据。This means that they also have property metadata, which individual classes can override. WPFWPF附加属性的作用域注意事项通常DependencyObject是在其上设置附加属性。The scoping considerations for an attached property in WPFWPF are generally that any DependencyObject can have an attached property set on them. 因此, 任何DependencyObject派生类都可以重写任何附加属性的元数据, 因为它可能是在类的实例上设置的。Therefore, any DependencyObject derived class can override the metadata for any attached property, as it might be set on an instance of the class. 可以重写默认值、回叫或 WPF 框架级别的特征报告属性。You can override default values, callbacks, or WPF framework-level characteristic-reporting properties. 如果针对类的实例设置了附加属性,则这些重写属性元数据特征将适用。If the attached property is set on an instance of your class, those override property metadata characteristics apply. 例如,可以重写默认值,这样,只要未以其他方式设置附加属性,重写值就会报告为类实例的附加属性的值。For instance, you can override the default value, such that your override value is reported as the value of the attached property on instances of your class, whenever the property is not otherwise set.

备注

Inherits属性与附加属性无关。The Inherits property is not relevant for attached properties.

将类作为现有依赖属性的所有者来添加Adding a Class as an Owner of an Existing Dependency Property

类可以使用AddOwner方法将自身添加为已注册的依赖属性的所有者。A class can add itself as an owner of a dependency property that has already been registered, by using the AddOwner method. 这使得该类可以使用最初针对另一个类型注册的依赖属性。This enables the class to use a dependency property that was originally registered for a different type. 添加类通常不是首先将该依赖属性注册为所有者的类型的派生类。The adding class is typically not a derived class of the type that first registered that dependency property as owner. 实际上,这使类及其派生类可以“继承”依赖属性实现,而不需要最初的所有者类,而且添加类也不必位于同一个实际的类层次结构中。Effectively, this allows your class and its derived classes to "inherit" a dependency property implementation without the original owner class and the adding class being in the same true class hierarchy. 另外,添加类(以及所有派生类)随后可以为最初的依赖属性提供特定于类型的元数据。In addition, the adding class (and all derived classes as well) can then provide type-specific metadata for the original dependency property.

添加类除了通过属性系统的实用工具方法将自身添加为所有者以外,还应当在自身声明其他公共成员,以使依赖属性向代码和标记公开,从而完全参与属性系统。As well as adding itself as owner through the property system utility methods, the adding class should declare additional public members on itself in order to make the dependency property] a full participant in the property system with exposure to both code and markup. 就为依赖属性公开对象模型而言,添加现有依赖属性的类与定义新的自定义依赖属性的类具有相同的职责。A class that adds an existing dependency property has the same responsibilities as far as exposing the object model for that dependency property as does a class that defines a new custom dependency property. 要公开的第一个此类成员是依赖属性标识符字段。The first such member to expose is a dependency property identifier field. 此字段应为public static readonly类型DependencyProperty为的字段, 该字段将分配给AddOwner调用的返回值。This field should be a public static readonly field of type DependencyProperty, which is assigned to the return value of the AddOwner call. 要定义的第二个成员是公共语言运行时 (CLR) "包装器" 属性。The second member to define is the common language runtime (CLR) "wrapper" property. 包装使你可以更方便地在代码中操作依赖属性 (避免SetValue每次调用, 并且只能在包装器中调用一次)。The wrapper makes it much more convenient to manipulate your dependency property in code (you avoid calls to SetValue each time, and can make that call only once in the wrapper itself). 包装器的实现方式与在注册自定义依赖属性时的实现方式完全相同。The wrapper is implemented identically to how it would be implemented if you were registering a custom dependency property. 有关实现依赖属性的详细信息,请参阅自定义依赖属性为依赖属性添加所有者类型For more information about implementing a dependency property, see Custom Dependency Properties and Add an Owner Type for a Dependency Property.

AddOwner 和附加属性AddOwner and Attached Properties

可以调用AddOwner由所有者类定义为附加属性的依赖属性。You can call AddOwner for a dependency property that is defined as an attached property by the owner class. 这样做的目的通常是为了将以前附加的属性作为非附加依赖属性来公开。Generally the reason for doing this is to expose the previously attached property as a non-attached dependency property. 然后, 你会将AddOwner返回值public static readonly公开为用作依赖项属性标识符的字段, 并将定义适当的 "包装器" 属性, 以便属性显示在成员表中并支持非附加属性类中的用法。You then will expose the AddOwner return value as a public static readonly field for use as the dependency property identifier, and will define appropriate "wrapper" properties so that the property appears in the members table and supports a non-attached property usage in your class.

请参阅See also