自定义依赖项属性Custom Dependency Properties

本主题介绍了 Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) 应用程序开发者和组件作者想要创建自定义依赖属性的原因,并介绍了一些可以提高属性的性能、可用性或通用性的实现步骤以及实现选项。This topic describes the reasons that Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) application developers and component authors might want to create custom dependency property, and describes the implementation steps as well as some implementation options that can improve performance, usability, or versatility of the property.

PrerequisitesPrerequisites

本主题假设你作为 WPFWPF 类的现有依赖属性的使用者已经对依赖属性有所了解,并且已经阅读了依赖属性概述主题。This topic assumes that you understand dependency properties from the perspective of a consumer of existing dependency properties on WPFWPF classes, and have read the Dependency Properties Overview topic. 若要理解本主题中的示例,还应当了解 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML) 并知道如何编写 WPFWPF 应用程序。In order to follow the examples in this topic, you should also understand 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML) and know how to write WPFWPF applications.

什么是依赖属性?What Is a Dependency Property?

您可以通过将其实现为依赖属性,使其成为公共语言运行时(CLR)属性,以支持样式设置、数据绑定、继承、动画和默认值。You can enable what would otherwise be a common language runtime (CLR) property to support styling, data binding, inheritance, animations, and default values by implementing it as a dependency property. 依赖属性是通过调用 Register 方法(或 RegisterReadOnly)注册到 WPFWPF 属性系统并且由 DependencyProperty 标识符字段支持的属性。Dependency properties are properties that are registered with the WPFWPF property system by calling the Register method (or RegisterReadOnly), and that are backed by a DependencyProperty identifier field. 依赖项属性只能由 DependencyObject 类型使用,但在 WPFWPF 类层次结构中 DependencyObject 非常高,因此 WPFWPF 中提供的大多数类都可以支持依赖属性。Dependency properties can be used only by DependencyObject types, but DependencyObject is quite high in the WPFWPF class hierarchy, so the majority of classes available in WPFWPF can support dependency properties. 有关依赖属性以及在此 SDK 中描述它们的一些术语和约定的详细信息,请参阅依赖属性概述For more information about dependency properties and some of the terminology and conventions used for describing them in this SDK, see Dependency Properties Overview.

依赖属性示例Examples of Dependency Properties

WPFWPF 类上实现的依赖属性的示例包括 Background 属性、Width 属性和 Text 属性,等等。Examples of dependency properties that are implemented on WPFWPF classes include the Background property, the Width property, and the Text property, among many others. 类公开的每个依赖项属性都具有一个对应的公共静态字段,该字段类型 DependencyProperty 在同一类上公开。Each dependency property exposed by a class has a corresponding public static field of type DependencyProperty exposed on that same class. 这是依赖属性的标识符。This is the identifier for the dependency property. 此标识符的命名约定为:依赖属性名称后面加上字符串 PropertyThe identifier is named using a convention: the name of the dependency property with the string Property appended to it. 例如,"Background" 属性的相应 DependencyProperty 标识符 "字段为" BackgroundProperty"。For example, the corresponding DependencyProperty identifier field for the Background property is BackgroundProperty. 该标识符存储有关已注册的依赖属性的信息,以后会将该标识符用于涉及依赖属性的其他操作,例如调用 SetValueThe identifier stores the information about the dependency property as it was registered, and the identifier is then used later for other operations involving the dependency property, such as calling SetValue.

依赖属性概述中所述,WPFWPF 中的所有依赖属性(大多数附加属性除外)也是 CLR 属性,因为 "包装器" 实现。As mentioned in the Dependency Properties Overview, all dependency properties in WPFWPF (except most attached properties) are also CLR properties because of the "wrapper" implementation. 因此,可以从代码中获取或设置依赖属性,方法是调用定义包装的 CLR 访问器,方法与使用其他 CLR 属性的方式相同。Therefore, from code, you can get or set dependency properties by calling CLR accessors that define the wrappers in the same manner that you would use other CLR properties. 作为已建立的依赖项属性的使用者,通常不使用 DependencyObject 方法 GetValueSetValue,这是基础属性系统的连接点。As a consumer of established dependency properties, you do not typically use the DependencyObject methods GetValue and SetValue, which are the connection point to the underlying property system. 相反,CLR 属性的现有实现已在属性的 getset 包装实现中调用 GetValueSetValue,并相应地使用标识符字段。Rather, the existing implementation of the CLR properties will have already called GetValue and SetValue within the get and set wrapper implementations of the property, using the identifier field appropriately. 若要自己实现自定义依赖属性,则需要使用类似的方法定义包装器。If you are implementing a custom dependency property yourself, then you will be defining the wrapper in a similar way.

应该何时实现依赖属性?When Should You Implement a Dependency Property?

实现类的属性时,只要类派生自 DependencyObject,就可以选择使用 DependencyProperty 标识符来备份属性,从而使其成为依赖属性。When you implement a property on a class, so long as your class derives from DependencyObject, you have the option to back your property with a DependencyProperty identifier and thus to make it a dependency property. 不必总是将属性实现为依赖属性,这不一定合适,具体取决于方案需要。Having your property be a dependency property is not always necessary or appropriate, and will depend on your scenario needs. 有时,使用私有字段支持属性的通常方法已足够满足需求。Sometimes, the typical technique of backing your property with a private field is adequate. 但是,如果要使属性支持以下一个或多个 WPFWPF 功能,则应该将属性实现为依赖属性:However, you should implement your property as a dependency property whenever you want your property to support one or more of the following WPFWPF capabilities:

  • 需要可以在样式中设置属性。You want your property to be settable in a style. 有关详细信息,请参阅样式设置和模板化For more information, see Styling and Templating.

  • 需要属性支持数据绑定。You want your property to support data binding. 有关数据绑定依赖属性的详细信息,请参阅绑定两个控件的属性For more information about data binding dependency properties, see Bind the Properties of Two Controls.

  • 需要可以使用动态资源引用设置属性。You want your property to be settable with a dynamic resource reference. 有关详细信息,请参阅 XAML 资源For more information, see XAML Resources.

  • 需要从元素树中的父元素自动继承属性值。You want to inherit a property value automatically from a parent element in the element tree. 在这种情况下,请使用 RegisterAttached 方法进行注册,即使你还创建了用于 CLR 访问的属性包装。In this case, register with the RegisterAttached method, even if you also create a property wrapper for CLR access. 有关详细信息,请参阅属性值继承For more information, see Property Value Inheritance.

  • 需要属性可以进行动画处理。You want your property to be animatable. 有关详细信息,请参阅 动画概述For more information, see Animation Overview.

  • 需要属性系统在先前的值因属性系统、环境或用户执行的操作而发生更改,或者因读取和使用样式而发生更改时进行报告。You want the property system to report when the previous value of the property has been changed by actions taken by the property system, the environment, or the user, or by reading and using styles. 通过使用属性元素据,属性可以指定回调方法,每次属性系统确定属性值已明确改动时将调用此回调方法。By using property metadata, your property can specify a callback method that will be invoked each time the property system determines that your property value was definitively changed. 与此相关的一个概念是属性值强制转换。A related concept is property value coercion. 有关详细信息,请参阅依赖属性回调和验证For more information, see Dependency Property Callbacks and Validation.

  • 需要使用同时也被 WPFWPF 进程使用的已建立的元数据约定,例如报告更改属性值是否应需要布局系统重新安排元素的可视内容。You want to use established metadata conventions that are also used by WPFWPF processes, such as reporting whether changing a property value should require the layout system to recompose the visuals for an element. 或者需要能够使用元素据替代,以便派生类可以更改基于元数据的特性,例如默认值。Or you want to be able to use metadata overrides so that derived classes can change metadata-based characteristics such as the default value.

  • 您希望使用自定义控件的属性来接收 Visual Studio WPF 设计器支持,如 "属性" 窗口编辑。You want properties of a custom control to receive Visual Studio WPF Designer support, such as Properties window editing. 有关详细信息,请参阅控件创作概述For more information, see Control Authoring Overview.

检查这些方案时,还应考虑是否可以通过替代现有依赖属性的元素据而不是通过实现一个全新的属性来实现方案。When you examine these scenarios, you should also consider whether you can achieve your scenario by overriding the metadata of an existing dependency property, rather than implementing a completely new property. 元素据替代是否可行取决于方案以及方案与现有的 WPFWPF 依赖属性和类中的实现的相似度。Whether a metadata override is practical depends on your scenario and how closely that scenario resembles the implementation in existing WPFWPF dependency properties and classes. 有关替代现有属性上的元素据的详细信息,请参阅依赖属性元素据For more information about overriding metadata on existing properties, see Dependency Property Metadata.

定义依赖属性的检查清单Checklist for Defining a Dependency Property

定义依赖属性包含 4 个不同的概念。Defining a dependency property consists of four distinct concepts. 这些概念并不一定是严格的过程步骤,因为其中一些概念在实现中会被合并为一行代码:These concepts are not necessarily strict procedural steps, because some of these end up being combined as single lines of code in the implementation:

  • (可选)创建依赖属性的属性元素据。(Optional) Create property metadata for the dependency property.

  • 在属性系统中注册属性名称,并指定所有者类型和属性值类型。Register the property name with the property system, specifying an owner type and the type of the property value. 此外,还应指定属性元素据(如果用到)。Also specify the property metadata, if used.

  • DependencyProperty 标识符定义为所有者类型上的 public static readonly 字段。Define a DependencyProperty identifier as a public static readonly field on the owner type.

  • 定义一个 CLR "包装器" 属性,该属性的名称与依赖项属性的名称匹配。Define a CLR "wrapper" property whose name matches the name of the dependency property. 实现 CLR "包装器" 属性的 get,并 set 访问器连接到支持它的依赖项属性。Implement the CLR "wrapper" property's get and set accessors to connect with the dependency property that backs it.

在属性系统中注册属性Registering the Property with the Property System

为使属性成为依赖属性,必须在属性系统维护的表中注册该属性,并为属性指定一个唯一标识符。此唯一标识符会用作后续属性系统操作的限定符。In order for your property to be a dependency property, you must register that property into a table maintained by the property system, and give it a unique identifier that is used as the qualifier for later property system operations. 这些操作可能是内部操作,也可能是你自己的代码调用属性系统 Api。These operations might be internal operations, or your own code calling property system APIs. 若要注册属性,请在类(类中,但在任何成员定义之外)的正文中调用 Register 方法。To register the property, you call the Register method within the body of your class (inside the class, but outside of any member definitions). "标识符" 字段也由 Register 方法调用提供,作为返回值。The identifier field is also provided by the Register method call, as the return value. Register 调用在其他成员定义之外完成的原因是,使用此返回值分配和创建 public static DependencyProperty 类型 readonly 字段字段作为类的一部分。The reason that the Register call is done outside of other member definitions is because you use this return value to assign and create a public static readonly field of type DependencyProperty as part of your class. 此字段会作为依赖属性的标识符。This field becomes the identifier for your dependency property.

public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
  "AquariumGraphic",
  typeof(Uri),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(null,
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnUriChanged)
  )
);
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty = DependencyProperty.Register("AquariumGraphic", GetType(Uri), GetType(AquariumObject), New FrameworkPropertyMetadata(Nothing, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnUriChanged)))

依赖属性命名约定Dependency Property Name Conventions

必需完全遵循已有的依赖属性命名约定,例外情况除外。There are established naming conventions regarding dependency properties that you must follow in all but exceptional circumstances.

依赖属性本身将有一个基本名称 "AquariumGraphic",如本示例所示,它作为 Register的第一个参数。The dependency property itself will have a basic name, "AquariumGraphic" as in this example, which is given as the first parameter of Register. 此名称在每个注册类型内必须唯一。That name must be unique within each registering type. 通过基类型继承的依赖属性会被视为注册类型的已有部分;无法再次注册已继承属性的名称。Dependency properties inherited through base types are considered to be already part of the registering type; names of inherited properties cannot be registered again. 但是,即使不继承依赖属性,也有方法可将类添加为依赖属性的所有者;有关详细信息,请参阅依赖属性元素据However, there is a technique for adding a class as owner of a dependency property even when that dependency property is not inherited; for details, see Dependency Property Metadata.

创建标识符字段时,按注册时的属性名称命名此字段,再加上后缀 PropertyWhen you create the identifier field, name this field by the name of the property as you registered it, plus the suffix Property. 此字段是依赖项属性的标识符,稍后会将其用作 SetValue 的输入,并将其作为你将在包装中进行的 GetValue 调用的输入,由你自己的代码访问属性,由属性系统支持的任何外部代码访问,并可能会 XAMLXAML 处理器。This field is your identifier for the dependency property, and it will be used later as an input for the SetValue and GetValue calls you will make in the wrappers, by any other code access to the property by your own code, by any external code access you allow, by the property system, and potentially by XAMLXAML processors.

备注

在类的主体中定义依赖属性是典型的实现,但也可以在类静态构造函数中定义依赖属性。Defining the dependency property in the class body is the typical implementation, but it is also possible to define a dependency property in the class static constructor. 需要多行代码来初始化依赖属性时,此方法会很有用。This approach might make sense if you need more than one line of code to initialize the dependency property.

实现“包装器”Implementing the "Wrapper"

包装实现应在 get 实现中调用 GetValue,并在 set 实现中 SetValue (最初的注册调用和字段在此处显示)。Your wrapper implementation should call GetValue in the get implementation, and SetValue in the set implementation (the original registration call and field are shown here too for clarity).

除异常情况以外,包装实现只能分别执行 GetValueSetValue 操作。In all but exceptional circumstances, your wrapper implementations should perform only the GetValue and SetValue actions, respectively. 其原因请参阅 XAML 加载和依赖属性主题。The reason for this is discussed in the topic XAML Loading and Dependency Properties.

WPFWPF 类上提供的所有现有公共依赖属性都使用这一简单的包装器实现模型;大多数情况下,依赖属性工作原理的复杂性本质上在于它是属性系统的行为,还是通过其他概念(例如强制转换或通过属性元数据进行的属性更改回调)实现的行为。All existing public dependency properties that are provided on the WPFWPF classes use this simple wrapper implementation model; most of the complexity of how dependency properties work is either inherently a behavior of the property system, or is implemented through other concepts such as coercion or property change callbacks through property metadata.


public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
  "AquariumGraphic",
  typeof(Uri),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(null,
      FrameworkPropertyMetadataOptions.AffectsRender, 
      new PropertyChangedCallback(OnUriChanged)
  )
);
public Uri AquariumGraphic
{
  get { return (Uri)GetValue(AquariumGraphicProperty); }
  set { SetValue(AquariumGraphicProperty, value); }
}

Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty = DependencyProperty.Register("AquariumGraphic", GetType(Uri), GetType(AquariumObject), New FrameworkPropertyMetadata(Nothing, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnUriChanged)))
Public Property AquariumGraphic() As Uri
    Get
        Return CType(GetValue(AquariumGraphicProperty), Uri)
    End Get
    Set(ByVal value As Uri)
        SetValue(AquariumGraphicProperty, value)
    End Set
End Property

同样,按照约定,包装属性的名称必须与所选的名称相同,并指定为注册该属性的 Register 调用的第一个参数。Again, by convention, the name of the wrapper property must be the same as the name chosen and given as first parameter of the Register call that registered the property. 如果属性不遵从此约定,尽管不一定会禁用所有可能的用法,但你会遇到几个比较突出的问题:If your property does not follow the convention, this does not necessarily disable all possible uses, but you will encounter several notable issues:

  • 样式和模板的某些方面不起作用。Certain aspects of styles and templates will not work.

  • 大多数工具和设计器必须依赖命名约定,才能正确序列化 XAMLXAML 或在每个属性级别提供设计器环境帮助。Most tools and designers must rely on the naming conventions to properly serialize XAMLXAML, or to provide designer environment assistance at a per-property level.

  • 处理特性值时,WPFWPF XAMLXAML 加载程序的会完全跳过包装器,并依赖于命名约定。The current implementation of the WPFWPF XAMLXAML loader bypasses the wrappers entirely, and relies on the naming convention when processing attribute values. 有关详细信息,请参阅 XAML 加载和依赖属性For more information, see XAML Loading and Dependency Properties.

新依赖属性的属性元数据Property Metadata for a New Dependency Property

注册依赖属性时,通过属性系统进行注册会创建一个存储属性特征的元素据对象。When you register a dependency property, the registration through the property system creates a metadata object that stores property characteristics. 其中的许多特性都具有默认值,如果将属性注册到 Register的简单签名,则会设置这些默认值。Many of these characteristics have defaults that are set if the property is registered with the simple signatures of Register. 其他签名 Register 允许您在注册属性时指定所需的元数据。Other signatures of Register allow you to specify the metadata that you want as you register the property. 为依赖属性使用的最常见元数据是为其使用默认值。该默认值适用于使用此属性的新实例。The most common metadata given for dependency properties is to give them a default value that is applied on new instances that use the property.

如果创建的依赖属性存在于 FrameworkElement的派生类中,则可以使用更专用的元数据类 FrameworkPropertyMetadata 而不是基 PropertyMetadata 类。If you are creating a dependency property that exists on a derived class of FrameworkElement, you can use the more specialized metadata class FrameworkPropertyMetadata rather than the base PropertyMetadata class. FrameworkPropertyMetadata 类的构造函数有多个签名,你可以在其中组合指定各种元数据特征。The constructor for the FrameworkPropertyMetadata class has several signatures where you can specify various metadata characteristics in combination. 如果只想指定默认值,请使用采用 Object类型的单个参数的签名。If you want to specify the default value only, use the signature that takes a single parameter of type Object. 将该对象参数传递为你的属性的特定于类型的默认值(提供的默认值必须为你作为 Register 调用中的 propertyType 参数提供的类型)。Pass that object parameter as a type-specific default value for your property (the default value provided must be the type you provided as the propertyType parameter in the Register call).

对于 FrameworkPropertyMetadata,还可以指定属性的元数据选项标志。For FrameworkPropertyMetadata, you can also specify metadata option flags for your property. 注册后这些标记会转换为属性元素据上的不同属性,并用于将某些条件传送给布局引擎等其他进程。These flags are converted into discrete properties on the property metadata after registration and are used to communicate certain conditionals to other processes such as the layout engine.

设置合适的元数据标记Setting Appropriate Metadata Flags

  • 如果您的属性(或其值的更改)影响 用户界面 (UI)user interface (UI),特别影响布局系统应如何调整页面中元素的大小或呈现元素,请设置以下一个或多个标志: AffectsMeasureAffectsArrangeAffectsRenderIf your property (or changes in its value) affects the 用户界面 (UI)user interface (UI), and in particular affects how the layout system should size or render your element in a page, set one or more of the following flags: AffectsMeasure, AffectsArrange, AffectsRender.

    • AffectsMeasure 指示对此属性的更改需要更改 UIUI 呈现,其中包含对象在父项中可能需要更多或更少的空间。AffectsMeasure indicates that a change to this property requires a change to UIUI rendering where the containing object might require more or less space within the parent. 例如,“宽度”属性应该设置此标记。For example, a "Width" property should have this flag set.

    • AffectsArrange 指示对此属性的更改需要更改 UIUI 呈现,这通常不需要在专用空间中进行更改,而是指示空间中的位置已更改。AffectsArrange indicates that a change to this property requires a change to UIUI rendering that typically does not require a change in the dedicated space, but does indicate that the positioning within the space has changed. 例如,“对齐”属性应该设置此标记。For example, an "Alignment" property should have this flag set.

    • AffectsRender 指示发生了其他一些更改,这些更改不会影响布局和度量值,但需要其他呈现。AffectsRender indicates that some other change has occurred that will not affect layout and measure, but does require another render. 更改现有元素的颜色的属性便是一个示例,例如“背景”。An example would be a property that changes a color of an existing element, such as "Background".

    • 对属性系统或布局回调进行自己的替代实现时,这些标记通常用作元数据中的协议。These flags are often used as a protocol in metadata for your own override implementations of property system or layout callbacks. 例如,如果实例的任何属性报告值更改并在其元数据中具有 true AffectsArrange,则可以使用 OnPropertyChanged 回调来调用 InvalidateArrangeFor instance, you might have an OnPropertyChanged callback that will call InvalidateArrange if any property of the instance reports a value change and has AffectsArrange as true in its metadata.

  • 超出上述所需大小时,某些属性可能会影响所含父元素的呈现特征。Some properties may affect the rendering characteristics of the containing parent element, in ways above and beyond the changes in required size mentioned above. 例如,在流文档模型中使用的 MinOrphanLines 属性,其中对该属性的更改可以更改包含该段落的流文档的总体呈现。An example is the MinOrphanLines property used in the flow document model, where changes to that property can change the overall rendering of the flow document that contains the paragraph. 使用 AffectsParentArrangeAffectsParentMeasure 来识别您自己的属性中的相似事例。Use AffectsParentArrange or AffectsParentMeasure to identify similar cases in your own properties.

  • 默认情况下,依赖属性支持数据绑定。By default, dependency properties support data binding. 在无实际的数据绑定方案或大型对象的数据绑定性能构成问题的情况下,可有意禁用数据绑定。You can deliberately disable data binding, for cases where there is no realistic scenario for data binding, or where performance in data binding for a large object is recognized as a problem.

  • 默认情况下,依赖属性 Mode 的数据绑定默认为 OneWayBy default, data binding Mode for dependency properties defaults to OneWay. 您始终可以将绑定更改为每个绑定实例 TwoWay;有关详细信息,请参阅指定绑定的方向You can always change the binding to be TwoWay per binding instance; for details, see Specify the Direction of the Binding. 但作为依赖属性作者,你可以选择在默认情况下将属性用于 TwoWay 绑定模式。But as the dependency property author, you can choose to make the property use TwoWay binding mode by default. MenuItem.IsSubmenuOpen了现有依赖属性的示例;此属性的方案是 IsSubmenuOpen 设置逻辑和 MenuItem 的组合与默认主题样式交互。An example of an existing dependency property is MenuItem.IsSubmenuOpen; the scenario for this property is that the IsSubmenuOpen setting logic and the compositing of MenuItem interact with the default theme style. IsSubmenuOpen 属性逻辑使用数据绑定来根据其他状态属性和方法调用来维护属性的状态。The IsSubmenuOpen property logic uses data binding natively to maintain the state of the property in accordance to other state properties and method calls. 默认情况下,绑定 TwoWay 的另一个示例属性为 TextBox.TextAnother example property that binds TwoWay by default is TextBox.Text.

  • 还可以通过设置 Inherits 标志来启用自定义依赖属性中的属性继承。You can also enable property inheritance in a custom dependency property by setting the Inherits flag. 在父元素和子元素具有相同属性的情况中,属性继承非常有用,它可以使子元素将该特定属性值设置为与父元素设置的值相同。Property inheritance is useful for a scenario where parent elements and child elements have a property in common, and it makes sense for the child elements to have that particular property value set to the same value as the parent set it. 示例可 DataContext可继承属性,该属性用于绑定操作,以便为数据呈现启用重要的主-从方案。An example inheritable property is DataContext, which is used for binding operations to enable the important master-detail scenario for data presentation. 通过使 DataContext 可继承,任何子元素也会继承该数据上下文。By making DataContext inheritable, any child elements inherit that data context also. 因为使用了属性值继承,你可以在页面或应用程序根目录上指定数据上下文,而无需对所有可能子元素中的绑定重新指定上下文。Because of property value inheritance, you can specify a data context at the page or application root, and do not need to respecify it for bindings in all possible child elements. DataContext 也是一个很好的示例,用于说明继承重写默认值,但它始终可以在任何特定的子元素上本地设置;有关详细信息,请参阅对分层数据使用主-从模式DataContext is also a good example to illustrate that inheritance overrides the default value, but it can always be set locally on any particular child element; for details, see Use the Master-Detail Pattern with Hierarchical Data. 属性值继承确实可能存在性能成本,因此应谨慎使用;有关详细信息,请参阅属性值继承Property value inheritance does have a possible performance cost, and thus should be used sparingly; for details, see Property Value Inheritance.

  • Journal 标志设置为,以指示是否应检测依赖属性或导航日记服务使用依赖属性。Set the Journal flag to indicate if your dependency property should be detected or used by navigation journaling services. 例如 SelectedIndex 属性;导航日志记录历史记录时,选择控件中选定的任何项都应保留。An example is the SelectedIndex property; any item selected in a selection control should be persisted when the journaling history is navigated.

只读依赖项属性Read-Only Dependency Properties

可以定义只读的依赖属性。You can define a dependency property that is read-only. 但是,为何将属性定义为只读的情况略有不同,其过程与在属性系统中注册属性并公开标识符相同。However, the scenarios for why you might define your property as read-only are somewhat different, as is the procedure for registering them with the property system and exposing the identifier. 有关详细信息,请参阅只读依赖属性For more information, see Read-Only Dependency Properties.

集合类型依赖项属性Collection-Type Dependency Properties

集合类型依赖属性要考虑一些其他实现问题。Collection-type dependency properties have some additional implementation issues to consider. 有关详细信息,请参阅集合类型依赖属性For details, see Collection-Type Dependency Properties.

依赖属性安全注意事项Dependency Property Security Considerations

依赖属性应声明为公共属性。Dependency properties should be declared as public properties. 依赖属性标识符字段应声明为公共静态字段。Dependency property identifier fields should be declared as public static fields. 即使您尝试声明其他访问级别(如受保护),也始终可以通过标识符与属性系统 Api 一起访问依赖属性。Even if you attempt to declare other access levels (such as protected), a dependency property can always be accessed through the identifier in combination with the property system APIs. 即使是受保护的标识符字段也可能是可访问的,因为元数据报告或值确定 Api 是属性系统的一部分,如 LocalValueEnumeratorEven a protected identifier field is potentially accessible because of metadata reporting or value determination APIs that are part of the property system, such as LocalValueEnumerator. 有关详细信息,请参阅依赖属性的安全性For more information, see Dependency Property Security.

依赖属性和类构造函数Dependency Properties and Class Constructors

托管代码编程(通常通过FxCop 等代码分析工具强制执行)的一般原则是:类构造函数不应调用虚方法。There is a general principle in managed code programming (often enforced by code analysis tools such as FxCop) that class constructors should not call virtual methods. 这是因为构造函数可以作为派生的类构造函数的基本初始化来调用,并且可能会在所构造的对象实例不完全初始化状态下通过构造函数输入虚方法。This is because constructors can be called as base initialization of a derived class constructor, and entering the virtual method through the constructor might occur at an incomplete initialization state of the object instance being constructed. 当从已从 DependencyObject派生的任何类派生时,应注意属性系统本身在内部调用并公开了虚方法。When you derive from any class that already derives from DependencyObject, you should be aware that the property system itself calls and exposes virtual methods internally. 这些虚方法属于 WPFWPF 属性系统服务。These virtual methods are part of the WPFWPF property system services. 替代方法会使派生类参与值确定。Overriding the methods enables derived classes to participate in value determination. 为避免运行时初始化出现潜在问题,,不应该在类的构造函数中设置依赖属性值,除非遵循特定的构造函数模式进行操作。To avoid potential issues with runtime initialization, you should not set dependency property values within constructors of classes, unless you follow a very specific constructor pattern. 有关详细信息,请参阅 DependencyObject 的安全构造函数模式For details, see Safe Constructor Patterns for DependencyObjects.

请参阅See also