依赖属性概述Dependency properties overview

本主题介绍了在使用 C++、C# 或 Visual Basic 编写 Windows 运行时应用以及 UI 的 XAML 定义时可用的依赖属性系统。This topic explains the dependency property system that is available when you write a Windows Runtime app using C++, C#, or Visual Basic along with XAML definitions for UI.

什么是依赖属性?What is a dependency property?

依赖属性是一种特定类型的属性。A dependency property is a specialized type of property. 这种属性的特殊之处在于,其属性值受到 Windows 运行时中专用属性系统的跟踪和影响。Specifically it's a property where the property's value is tracked and influenced by a dedicated property system that is part of the Windows Runtime.

为了支持依赖属性,定义该属性的对象必须是一个 DependencyObject(也就是说,一个在其继承中的某个位置具有 DependencyObject 基类的类)。In order to support a dependency property, the object that defines the property must be a DependencyObject (in other words a class that has the DependencyObject base class somewhere in its inheritance). 使用 XAML 的 UWP 应用都将使用的 UI 定义的类型的许多DependencyObject子类,并将支持依赖项属性。Many of the types you use for your UI definitions for a UWP app with XAML will be a DependencyObject subclass, and will support dependency properties. 但是,对于任何来自 Windows 运行时命名空间的类型,如果其名称中没有“XAML”,便不支持依赖属性;这种类型的属性都是普通属性,它们不具有属性系统的依赖行为。However, any type that comes from a Windows Runtime namespace that doesn't have "XAML" in its name won't support dependency properties; properties of such types are ordinary properties that won't have the property system's dependency behavior.

依赖属性的用途是提供一种系统方式,用来基于其他输入(在应用运行时其内部出现的其他属性、事件和状态)计算属性的值。The purpose of dependency properties is to provide a systemic way to compute the value of a property based on other inputs (other properties, events and states that occur within your app while it runs). 其他输入可能包括:These other inputs might include:

  • 外部输入,例如用户首选项External input such as user preference
  • 即时属性确定机制,例如数据绑定、动画和故事板Just-in-time property determination mechanisms such as data binding, animations and storyboards
  • 多用途模板模式,例如资源和样式Multiple-use templating patterns such as resources and styles
  • 通过与对象树中其他元素的父子关系知道的值Values known through parent-child relationships with other elements in the object tree

依赖项属性表示或支持的编程模型的特定功能的用于定义包含 XAML 的 Windows 运行时应用的 UI 和C#,Microsoft Visual Basic 或视觉对象C++组件扩展 (C++/CX) 代码。A dependency property represents or supports a specific feature of the programming model for defining a Windows Runtime app with XAML for UI and C#, Microsoft Visual Basic or Visual C++ component extensions (C++/CX) for code. 这些功能包括:These features include:

  • 数据绑定Data binding
  • 样式Styles
  • 情节提要动画Storyboarded animations
  • “PropertyChanged”行;一种依赖属性,实现该依赖属性可提供回调,从而将更改传播给其他依赖属性"PropertyChanged" behavior; a dependency property can be implemented to provide callbacks that can propagate changes to other dependency properties
  • 使用来自属性元数据的默认值Using a default value that comes from property metadata
  • 一般属性系统实用工具,例如 ClearValue 和元数据查找General property system utility such as ClearValue and metadata lookup

依赖属性和 Windows 运行时属性Dependency properties and Windows Runtime properties

依赖属性提供一种全局内部属性存储来在运行时支持应用内的所有依赖属性,从而扩展基本的 Windows 运行时属性功能。Dependency properties extend basic Windows Runtime property functionality by providing a global, internal property store that backs all of the dependency properties in an app at run time. 这种方法可以替代为具有专用字段的属性(在属性定义类中为专用)提供支持的标准模式。This is an alternative to the standard pattern of backing a property with a private field that's private in the property-definition class. 你可以将此内部属性存储视为任何特定对象的一组属性标识符和值(只要该对象是 DependencyObject 即可)。You can think of this internal property store as being a set of property identifiers and values that exist for any particular object (so long as it's a DependencyObject). 存储中的每个属性均通过 DependencyProperty 实例(而不是通过名称)进行标识。Rather than being identified by name, each property in the store is identified by a DependencyProperty instance. 但是,大多数情况下,属性系统会隐藏该实现详细信息:你可以使用简单名称(你所使用的代码语言中的可编程属性名称,或是在编写 XAML 时使用的属性名称)频繁访问依赖属性。However, the property system mostly hides this implementation detail: you can usually access dependency properties by using a simple name (the programmatic property name in the code language you're using, or an attribute name when you're writing XAML).

提供依赖属性系统支持的基类型为 DependencyObjectThe base type that provides the underpinnings of the dependency property system is DependencyObject. DependencyObject 定义可访问依赖属性的方法,并且 DependencyObject 派生类的实例在内部支持我们之前提及的属性存储概念。DependencyObject defines methods that can access the dependency property, and instances of a DependencyObject derived class internally support the property store concept we mentioned earlier.

下面总结了本文在探讨依赖属性时使用的术语:Here is a summation of the terminology that we use in the documentation when discussing dependency properties:

术语Term 描述Description
依赖属性Dependency property 存在于 DependencyProperty 标识符上的一个属性(如下所示)。A property that exists on a DependencyProperty identifier (see below). 通常该标识符可用作定义 DependencyObject 派生类的一个静态成员。Usually this identifier is available as a static member of the defining DependencyObject derived class.
依赖属性标识符Dependency property identifier 用于标识属性的常量值,它通常公开显示且只读。A constant value to identify the property, it is typically public and read-only.
属性包装器Property wrapper Windows 运行时属性的可调用 getset 实现。The callable get and set implementations for a Windows Runtime property. 或者原始定义的特定于语言的投影。Or, the language-specific projection of the original definition. get 属性包装器实现调用 GetValue,传递相关的依赖属性标识符。A get property wrapper implementation calls GetValue, passing the relevant dependency property identifier.

属性包装器不仅给调用方带来了方便,它还向任何为属性使用 Windows 运行时定义的过程、工具或投影公开该依赖属性。The property wrapper is not just convenience for callers, it also exposes the dependency property to any process, tool or projection that uses Windows Runtime definitions for properties.

下面的示例定义一个自定义“IsSpinning”依赖属性,就像 C# 中的定义一样,然后显示依赖属性标识符与属性包装器之间的关系。The following example defines a custom "IsSpinning" dependency property as defined for C#, and shows the relationship of the dependency property identifier to the property wrapper.

// IsSpinningProperty is the dependency property identifier
// no need for info in the last PropertyMetadata parameter, so we pass null
public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
        "IsSpinning", typeof(Boolean),
        typeof(ExampleClass), null
    );
// The property wrapper, so that callers can use this property through a simple ExampleClassInstance.IsSpinning usage rather than requiring property system APIs
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

备注

前面的示例中不是完整的示例演示如何创建自定义依赖属性。The preceding example is not intended as the complete example for how to create a custom dependency property. 它旨在为希望通过代码学习概念的人说明依赖属性概念。It is intended to show dependency property concepts for anyone that prefers learning concepts through code. 有关更为完整的示例,请参阅自定义依赖属性For a more complete example, see Custom dependency properties.

依赖属性值优先级Dependency property value precedence

当获得一个依赖属性的值时,你获得的值是通过任何一个参与 Windows 运行时属性系统的输入,针对该属性确定的。When you get the value of a dependency property, you are obtaining a value that was determined for that property through any one of the inputs that participate in the Windows Runtime property system. 依赖属性值存在优先级,因此 Windows 运行时属性系统可通过一种可预测的方式计算值,并且你需要熟悉基本的优先级顺序,这一点很重要。Dependency property value precedence exists so that the Windows Runtime property system can calculate values in a predictable way, and it's important that you be familiar with the basic precedence order too. 否则你可能会遇到这样的情况:当你尝试在一个优先级别设置某个属性时,某些东西(系统、第三方调用方、你自己的代码)却在另一个级别设置了该属性,你会很难明白使用了哪个属性值以及该值的原始位置。Otherwise, you might find yourself in a situation where you're trying to set a property at one level of precedence but something else (the system, third-party callers, some of your own code) is setting it at another level, and you'll get frustrated trying to figure out which property value is used and where that value came from.

例如,样式和模板用作建立属性值并因此建立控件外观的一个共同起点。For example, styles and templates are intended to be a shared starting point for establishing property values and thus appearances of a control. 但在一个特定的控件实例上,你可能希望更改它的值,而不是更改通用模板化值,例如为该控件提供一种不同的背景颜色或提供一种不同的文本字符串作为内容。But on a particular control instance you might want to change its value versus the common templated value, such as giving that control a different background color or a different text string as content. Windows 运行时属性系统认为本地值的优先级比样式和模板所提供的值的优先级更高。The Windows Runtime property system considers local values at higher precedence than values provided by styles and templates. 这使方案可以使用特定于应用的值覆盖模板,以便你可以在应用 UI 中自行使用这些控件。That enables the scenario of having app-specific values overwrite the templates so that the controls are useful for your own use of them in app UI.

依赖属性优先级列表Dependency property precedence list

以下是属性系统在分配依赖属性的运行时值时采用的明确顺序。The following is the definitive order that the property system uses when assigning the run-time value for a dependency property. 优先级最高的会首先列出。Highest precedence is listed first. 你将找到比此列表更加详细的解释。You'll find more detailed explanations just past this list.

  1. 经过动画处理的值: 活动动画、 可视状态动画或具有动画 HoldEnd 行为。Animated values: Active animations, visual state animations, or animations with a HoldEnd behavior. 若要拥有任何实用效果,则适用于属性的动画必须拥有比基础(无动画)值更高的优先级,即使该值进行了本地设置也是如此。To have any practical effect, an animation applied to a property must have precedence over the base (unanimated) value, even if that value was set locally.
  2. 本地值: 可能会通过属性包装器,这也相当于为属性或属性元素在 XAML,或通过调用设置的方便地设置本地值 SetValue 方法使用的属性特定的实例。Local value: A local value might be set through the convenience of the property wrapper, which also equates to setting as an attribute or property element in XAML, or by a call to the SetValue method using a property of a specific instance. 如果使用绑定或静态资源来设置本地值,优先级列表中的每个操作都认为本地值已设置,如果设置了一个新本地值,绑定或资源引用将被清除。If you set a local value by using a binding or a static resource, these each act in the precedence as if a local value was set, and bindings or resource references are erased if a new local value is set.
  3. 模板化属性: 如果它作为模板的一部分创建的元素具有这些 (从 ControlTemplate DataTemplate)。Templated properties: An element has these if it was created as part of a template (from a ControlTemplate or DataTemplate).
  4. 样式资源库: 中的值 Setter 来自页面或应用程序资源的样式中。Style setters: Values from a Setter within styles from page or application resources.
  5. 默认值: 依赖属性可以有一个默认值作为其元数据的一部分。Default value: A dependency property can have a default value as part of its metadata.

模板属性Templated properties

模板属性作为一个优先级项,不适用于直接在 XAML 页面标记中声明的元素的任何属性。Templated properties as a precedence item do not apply to any property of an element that you declare directly in XAML page markup. 模板属性概念只适用于 Windows 运行时将 XAML 模板应用于 UI 元素并因此而定义其视觉效果时所创建的对象。The templated property concept exists only for objects that are created when the Windows Runtime applies a XAML template to a UI element and thus defines its visuals.

从控件模板中设置的所有属性都具有某些类型的值。All the properties that are set from a control template have values of some kind. 其中的大部分值都类似于控件的一组扩展的默认值,并且通常与你可以稍后通过直接设置属性值重置的值相关联。These values are almost like an extended set of default values for the control and are often associated with values you can reset later by setting the property values directly. 因此,必须将模板集值与真实的本地值区分开,以便任何新的本地值都可以覆盖它。Thus the template-set values must be distinguishable from a true local value, so that any new local value can overwrite it.

备注

在某些情况下,如果模板无法为本应可以在实例中设置的属性公开 {TemplateBinding} 标记扩展引用,则此模板甚至可能会替代本地值。In some cases the template might override even local values, if the template failed to expose {TemplateBinding} markup extension references for properties that should have been settable on instances. 通常只有在确实不准备在实例中设置相应属性的情况下才会进行上述替代,例如,当属性只是与视觉效果和模板行为相关,而与使用模板的控件的预期功能或运行时逻辑不相关时。This is usually done only if the property is really not intended to be set on instances, for example if it's only relevant to visuals and template behavior and not to the intended function or runtime logic of the control that uses the template.

绑定和优先级Bindings and precedence

绑定操作对于任何适用范围都具有相应的优先级。Binding operations have the appropriate precedence for whatever scope they're used for. 例如,对于应用于本地值的 {Binding},其作用相当于本地值;对于属性设置器应用的 {TemplateBinding} 标记扩展,其作用相当于样式设置器。For example, a {Binding} applied to a local value acts as local value, and a {TemplateBinding} markup extension for a property setter applies as a style setter does. 由于绑定必须一直等到运行时才能获取来自数据源的值,因此确定任何属性的属性值优先级这一过程也会延迟到运行时。Because bindings must wait until run-time to obtain values from data sources, the process of determining the property value precedence for any property extends into run-time as well.

绑定不仅具有与本地值相同的优先级,而且它们确实是本地值,区别在于绑定是延迟值的占位符。Not only do bindings operate at the same precedence as a local value, they really are a local value, where the binding is the placeholder for a value that is deferred. 如果一个属性值具有相应的绑定,则可在运行时为其设置一个本地值,用于完整替换该绑定。If you have a binding in place for a property value, and you set a local value on it at run-time, that replaces the binding entirely. 同样地,如果你通过调用 SetBinding 来定义只在运行时才存在的绑定,则会替换可能在 XAML 中应用过的所有本地值或之前执行的代码。Similarly, if you call SetBinding to define a binding that only comes into existence at run-time, you replace any local value you might have applied in XAML or with previously executed code.

情节提要动画和基值Storyboarded animations and base value

情节提要动画要根据基值的概念来执行。Storyboarded animations act on a concept of a base value. 基值是由属性系统使用其优先级确定的值,在确定过程中会省略查找动画的最后步骤。The base value is the value that's determined by the property system using its precedence, but omitting that last step of looking for animations. 例如,一个基值可能来自控件模板,也可能来自在某个控件实例中设置的本地值。For example, a base value might come from a control's template, or it might come from setting a local value on an instance of a control. 无论是上述哪种情况,只要你的动画继续运行,应用此动画便会覆盖此基值并应用动画值。Either way, applying an animation will overwrite this base value and apply the animated value for as long as your animation continues to run.

对于一个动画属性,如果该动画没有显式指定 FromTo,或如果动画在完成时将属性恢复到基值,那么基值仍然会影响动画的行为。For an animated property, the base value can still have an effect on the animation's behavior, if that animation does not explicitly specify both From and To, or if the animation reverts the property to its base value when completed. 在这些情况下,一旦动画停止运行,便会再次使用余下的优先级。In these cases, once an animation is no longer running, the rest of the precedence is used again.

但是,如果动画为 HoldEnd 行为指定了 To,则在动画被删除以前,它可以一直替代本地值,甚至当动画在视觉上看似已经停止时也是如此。However, an animation that specifies a To with a HoldEnd behavior can override a local value until the animation is removed, even when it visually appears to be stopped. 从概念上来说,这类似于永久运行的动画,即使在 UI 中没有可视动画时也是如此。Conceptually this is like an animation that's running forever even if there is not a visual animation in the UI.

可将多个动画应用于一个属性。Multiple animations can be applied to a single property. 这其中每个动画都可能经过定义,以替换来自值优先级中不同点的基值。Each of these animations might have been defined to replace base values that came from different points in the value precedence. 但是,在运行时这些动画将同时运行,这通常意味着动画必须将它们的值组合起来,因为每个动画对值都具有同等的影响。However, these animations will all be running simultaneously at run time, and that often means that they must combine their values because each animation has equal influence on the value. 这取决于定义动画的方式和动画值的类型。This depends on exactly how the animations are defined, and the type of the value that is being animated.

有关详细信息,请参阅情节提要动画For more info, see Storyboarded animations.

默认值Default values

有关使用 PropertyMetadata 值为依赖属性创建默认值的详细信息,请参阅自定义依赖属性主题。Establishing the default value for a dependency property with a PropertyMetadata value is explained in more detail in the Custom dependency properties topic.

即使并未在依赖属性的元数据中显式定义默认值,依赖属性仍然具有这些默认值。Dependency properties still have default values even if those default values weren't explicitly defined in that property's metadata. 除非 Windows 运行时依赖属性的默认值由元数据进行更改,否则它们通常都是以下属性之一:Unless they have been changed by metadata, default values for the Windows Runtime dependency properties are generally one of the following:

  • 使用运行时对象或基本 Object 类型(一种引用类型)的属性的默认值为 nullA property that uses a run-time object or the basic Object type (a reference type) has a default value of null. 例如,在特意设置 DataContext 或被继承之前,它的值一直会是 nullFor example, DataContext is null until it's deliberately set or is inherited.
  • 使用数字或布尔值(一种值类型)等基值的属性会使用预期的默认值作为该值。A property that uses a basic value such as numbers or a Boolean value (a value type) uses an expected default for that value. 例如,使用 0 作为整数和浮点数,使用 false 作为布尔值。For example, 0 for integers and floating-point numbers, false for a Boolean.
  • 使用 Windows 运行时结构的属性通过调用该结构的隐式默认构造函数获得默认值。A property that uses a Windows Runtime structure has a default value that's obtained by calling that structure's implicit default constructor. 该构造函数会在结构中的每一个基值字段中使用默认值。This constructor uses the defaults for each of the basic value fields of the structure. 例如,Point 值的默认值会通过其 XY 值初始化为 0。For example, a default for a Point value is initialized with its X and Y values as 0.
  • 使用枚举的属性以该枚举中首个定义成员的值为默认值。A property that uses an enumeration has a default value of the first defined member in that enumeration. 检查特定枚举的引用,以查明默认值。Check the reference for specific enumerations to see what the default value is.
  • 使用字符串的属性(用于 .NET 的 System.String,用于 C++/CX 的 Platform::String)以空字符串 ( "" ) 为默认值。A property that uses a string (System.String for .NET, Platform::String for C++/CX) has a default value of an empty string ("").
  • 集合属性通常不会实现为依赖属性,本主题进一步讨论了其原因。Collection properties aren't typically implemented as dependency properties, for reasons discussed further on in this topic. 但是如果你实现了自定义集合属性,并且你希望使其成为依赖属性,请避免意外的 singleton,如自定义依赖属性结尾部分所述。But if you implement a custom collection property and you want it to be a dependency property, make sure to avoid an unintentional singleton as described near the end of Custom dependency properties.

依赖属性提供的属性功能Property functionality provided by a dependency property

数据绑定Data binding

依赖属性可使它的值通过应用数据绑定进行设置。A dependency property can have its value set through applying a data binding. 数据绑定使用 XAML 中的 {Binding} 标记扩展语法、{x:Bind} 标记扩展或代码中的 Binding 类。Data binding uses the {Binding} markup extension syntax in XAML, {x:Bind} markup extension or the Binding class in code. 对于数据绑定属性,其属性值的最终确定要延迟到运行时。For a databound property, the final property value determination is deferred until run time. 届时,将从数据源中获取值。At that time the value is obtained from a data source. 依赖属性系统在这里所起到的作用是在值还未知时为诸如加载 XAML 等操作启用占位符行为,然后在运行时通过与 Windows 运行时数据绑定引擎交互来提供值。The role that the dependency property system plays here is enabling a placeholder behavior for operations like loading XAML when the value is not yet known, and then supplying the value at run time by interacting with the Windows Runtime data binding engine.

以下示例使用 XAML 中的绑定设置 TextBlock 元素的 Text 值。The following example sets the Text value for a TextBlock element, using a binding in XAML. 该绑定使用继承的数据上下文和对象数据源。The binding uses an inherited data context and an object data source. (这个简短示例中没有展示这些方面;有关展示上下文和来源的更完整示例,请参阅深入了解数据绑定。)(Neither of these is shown in the shortened example; for a more complete sample that shows context and source, see Data binding in depth.)

<Canvas>
  <TextBlock Text="{Binding Team.TeamName}"/>
</Canvas>

你也可以使用代码(而不是 XAML)来建立绑定。You can also establish bindings using code rather than XAML. 请参阅 SetBindingSee SetBinding.

备注

此类绑定被视为本地值的依赖项属性值优先级。Bindings like this are treated as a local value for purposes of dependency property value precedence. 如果你为最初存放 Binding 值的属性设置其他本地值,则将完全改写绑定,而不只是改写绑定的运行时值。If you set another local value for a property that originally held a Binding value, you will overwrite the binding entirely, not just the binding's run-time value. {x:Bind} 绑定使用生成的代码(将为该属性设置本地值)实现。{x:Bind} Bindings are implemented using generated code that will set a local value for the property. 如果为使用 {x:Bind} 的属性设置本地值,将在下次评估绑定时替换该值,例如在其源对象上观察属性更改时。If you set a local value for a property that is using {x:Bind}, then that value will be replaced the next time the binding is evaluated, such as when it observes a property change on its source object.

绑定源、绑定目标、FrameworkElement 的角色Binding sources, binding targets, the role of FrameworkElement

要作为绑定的来源,属性不需要是依赖属性;一般可以使用任何属性作为绑定源,不过这取决于你的编程语言,而且每个属性都具有特定的边缘方案。To be the source of a binding, a property does not need to be a dependency property; you can generally use any property as a binding source, although this depends on your programming language and each has certain edge cases. 但是,要作为 {Binding} 标记扩展Binding 的目标,该属性必须是依赖属性。However, to be the target of a {Binding} markup extension or Binding, that property must be a dependency property. {x:Bind} 没有此项要求,因为它使用生成的代码应用其绑定值。{x:Bind} does not have this requirement as it uses generated code to apply its binding values.

如果在代码中创建绑定,请注意 SetBinding API 仅为 FrameworkElement 定义。If you are creating a binding in code, note that the SetBinding API is defined only for FrameworkElement. 但是,也可以使用 BindingOperations 创建绑定定义,从而引用任何 DependencyObject 属性。However, you can create a binding definition using BindingOperations instead, and thus reference any DependencyObject property.

对于代码或 XAML,请记住 DataContext 是一个 FrameworkElement 属性。For either code or XAML, remember that DataContext is a FrameworkElement property. 通过使用一种父子属性继承的形式(通常在 XAML 标记中建立),绑定系统可解析父元素上存在的 DataContextBy using a form of parent-child property inheritance (typically established in XAML markup), the binding system can resolve a DataContext that exists on a parent element. 即使子对象(具有目标属性)不是 FrameworkElement 并且因此没有自身的 DataContext 值,此继承也可以进行评估。This inheritance can evaluate even if the child object (which has the target property) is not a FrameworkElement and therefore does not hold its own DataContext value. 但是,所继承的父元素必须是一个 FrameworkElement,才能设置和具有 DataContextHowever, the parent element being inherited must be a FrameworkElement in order to set and hold the DataContext. 否则,你必须定义绑定,这样它才可以使用 DataContextnull 值。Alternatively, you must define the binding such that it can function with a null value for DataContext.

对于大部分数据绑定方案,连接绑定并不是唯一需要的。Wiring the binding is not the only thing that's needed for most data binding scenarios. 要让单向或双向绑定生效,来源属性必须支持能够传播到绑定系统并进而传播到目标的更改通知。For a one-way or two-way binding to be effective, the source property must support change notifications that propagate to the binding system and thus the target. 对于自定义绑定源,这意味着该属性必须是依赖属性,或者该对象必须支持 INotifyPropertyChangedFor custom binding sources, this means that the property must be a dependency property, or the object must support INotifyPropertyChanged. 集合应支持 INotifyCollectionChangedCollections should support INotifyCollectionChanged. 某些类在其实现中支持这些接口,以便它们可在数据绑定方案中用作基类;这种类的一个示例是 ObservableCollection<T> Certain classes support these interfaces in their implementations so that they are useful as base classes for data binding scenarios; an example of such a class is ObservableCollection<T>. 有关数据绑定和数据绑定与属性系统之间关系的详细信息,请参阅深入了解数据绑定For more information on data binding and how data binding relates to the property system, see Data binding in depth.

备注

类型列出此处支持 Microsoft.NET 数据源。The types listed here support Microsoft .NET data sources. C++/CX 数据源可针对更改通知或可观察行为使用不同的接口,请参阅深入了解数据绑定C++/CX data sources use different interfaces for change notification or observable behavior, see Data binding in depth.

样式和模板Styles and templates

样式和模板是两种将属性定义为依赖属性的场景。Styles and templates are two of the scenarios for properties being defined as dependency properties. 样式对设置可定义应用 UI 的属性非常有用。Styles are useful for setting properties that define the app's UI. 样式在 XAML 中定义为资源,作为 Resources 集合中的一个条目,或者 XAML 文件(如主题资源字典)中的一个条目。Styles are defined as resources in XAML, either as an entry in a Resources collection, or in separate XAML files such as theme resource dictionaries. 样式与属性系统交互,因为它们包含属性的资源库。Styles interact with the property system because they contain setters for properties. 此处最重要的属性是 ControlControl.Template 属性:它定义 Control 的大部分可视外观和视觉状态。The most important property here is the Control.Template property of a Control: it defines most of the visual appearance and visual state for a Control. 有关样式和定义一个 Style 并使用资源库的某些示例 XAML 的详细信息,请参阅设置控件样式For more info on styles, and some example XAML that defines a Style and uses setters, see Styling controls.

来自样式或模板的值是延迟值,类似于绑定。Values that come from styles or templates are deferred values, similar to bindings. 这样,控件用户可以重新创建控件模板或重新定义样式。This is so that control users can re-template controls or redefine styles. 正因如此,样式中的属性设置器才只根据依赖属性(而非普通属性)来执行。And that's why property setters in styles can only act on dependency properties, not ordinary properties.

情节提要动画Storyboarded animations

你可以使用情节提要动画对依赖属性的值进行动画处理。You can animate a dependency property's value using a storyboarded animation. Windows 运行时中的情节提要动画不仅仅是视觉装饰。Storyboarded animations in the Windows Runtime are not merely visual decorations. 更有用的做法是将动画视为一种状态机技术,你可以通过该技术设置单个属性或所有属性的值以及控件的视觉效果,并可在日后更改这些值。It's more useful to think of animations as being a state machine technique that can set the values of individual properties or of all properties and visuals of a control, and change these values over time.

若要创建动画,动画的目标属性必须是一个依赖属性。To be animated, the animation's target property must be a dependency property. 此外,若要创建动画,目标属性的值类型必须受现有 Timeline 派生的动画类型之一支持。Also, to be animated, the target property's value type must be supported by one of the existing Timeline-derived animation types. ColorDoublePoint 的值可使用内插或关键帧技术实现动画效果。Values of Color, Double and Point can be animated using either interpolation or keyframe techniques. 大部分其他值都可以使用离散式 Object 关键帧实现动画效果。Most other values can be animated using discrete Object key frames.

当应用并运行一个动画时,动画值操作的优先级比该属性使用的任何其他值(例如本地值)更高。When an animation is applied and running, the animated value operates at a higher precedence than any value (such as a local value) that the property otherwise has. 动画还有一个可选的 HoldEnd 行为,该行为可能导致动画应用于属性值,即使动画在视觉上已停止也是如此。Animations also have an optional HoldEnd behavior that can cause animations to apply to property values even if the animation visually appears to be stopped.

状态机原则可通过在控件的 VisualStateManager 状态模型中使用情节提要动画来体现。The state machine principle is embodied by the use of storyboarded animations as part of the VisualStateManager state model for controls. 有关情节提要动画的详细信息,请参阅情节提要动画For more info on storyboarded animations, see Storyboarded animations. 有关 VisualStateManager 和定义控件视觉状态的详细信息,请参阅视觉状态的情节提要动画控件模板For more info on VisualStateManager and defining visual states for controls, see Storyboarded animations for visual states or Control templates.

属性已更改行为Property-changed behavior

属性已更改行为是依赖属性术语中“依赖”部分的一个主要原因。Property-changed behavior is the origin of the "dependency" part of dependency property terminology. 在另一个属性可以影响第一个属性值的情形下,维护一个属性的有效值是许多框架中一个很难的开发问题。Maintaining valid values for a property when another property can influence the first property's value is a difficult development problem in many frameworks. 在 Windows 运行时属性系统中,每个依赖属性可指定一个回调,只要它的属性值更改,就会调用该回调。In the Windows Runtime property system, each dependency property can specify a callback that is invoked whenever its property value changes. 此回调可用于通知或更改相关的属性值(通常采用一种同步方式)。This callback can be used to notify or change related property values, in a generally synchronous manner. 许多现有的依赖属性有一个属性已更改行为。Many existing dependency properties have a property-changed behavior. 也可以向自定义依赖属性添加类似的回调行为,实现你自己的属性已更改回调。You can also add similar callback behavior to custom dependency properties, and implement your own property-changed callbacks. 有关示例,请参阅自定义依赖属性See Custom dependency properties for an example.

Windows 10 引入了 RegisterPropertyChangedCallback 方法。Windows 10 introduces the RegisterPropertyChangedCallback method. 这使应用程序代码可以注册更改通知(如果指定的依赖属性在 DependencyObject 的实例上发生更改)。This enables application code to register for change notifications when the specified dependency property is changed on an instance of DependencyObject.

默认值和 ClearValueDefault value and ClearValue

一个依赖属性可在其属性元数据中定义一个默认值。A dependency property can have a default value defined as part of its property metadata. 对于依赖属性而言,在首次对该属性进行设置之后,其默认值并不会完全失效。For a dependency property, its default value doesn't become irrelevant after the property's been set the first time. 只要值优先级中其他某个决定因素消失,就可以在运行时再次应用默认值。The default value might apply again at run-time whenever some other determinant in value precedence disappears. (下一节讨论是依赖属性值优先级)。例如,你可能会有意删除的样式值或将应用到属性的动画,但你想要执行此操作后为合理的默认值的值。(Dependency property value precedence is discussed in the next section.) For example, you might deliberately remove a style value or an animation that applies to a property, but you want the value to be a reasonable default after you do so. 依赖属性默认值可以提供此值,无需将专门设置每个属性的值作为额外步骤。The dependency property default value can provide this value, without needing to specifically set each property's value as an extra step.

即使已使用本地值设置某个属性,你仍可以特意将其设置为默认值。You can deliberately set a property to the default value even after you have already set it with a local value. 若要再次将属性值重置为默认值,并且启用优先级中其他可能会替代默认值(而非本地值)的其他参与者,可以调用 ClearValue 方法(引用该属性以作为方法参数清除)。To reset a value to be the default again, and also to enable other participants in precedence that might override the default but not a local value, call the ClearValue method (reference the property to clear as a method parameter). 有时你可能并不希望属性固定使用默认值,但是清除本地值并还原为默认值可能会启用优先级中需要立即执行的其他项目,例如使用来自控制模板中样式资源库的值。You don't always want the property to literally use the default value, but clearing the local value and reverting to the default value might enable another item in precedence that you want to act now, such as using the value that came from a style setter in a control template.

DependencyObject 和线程处理DependencyObject and threading

所有 DependencyObject 实例都必须在与 Windows 运行时应用所显示的当前 Window 相关联的 UI 线程上创建。All DependencyObject instances must be created on the UI thread which is associated with the current Window that is shown by a Windows Runtime app. 虽然每个 DependencyObject 都必须在主 UI 线程上创建,但可以通过访问 Dispatcher 属性从其他线程使用调度程序引用来访问这些对象。Although each DependencyObject must be created on the main UI thread, the objects can be accessed using a dispatcher reference from other threads, by accessing the Dispatcher property. 然后,你可以在 CoreDispatcher 对象上调用诸如 RunAsync 的方法,并在 UI 线程上遵循线程限制规则执行你的代码。Then you can call methods such as RunAsync on the CoreDispatcher object, and execute your code within the rules of thread restrictions on the UI thread.

DependencyObject 的线程处理特性很重要,因为这通常意味着只有那些在 UI 线程上运行的代码才能更改或读取依赖属性的值。The threading aspects of DependencyObject are relevant because it generally means that only code that runs on the UI thread can change or even read the value of a dependency property. 在正确使用 async 模式和后台工作线程的典型 UI 代码中,通常可以避免线程处理问题。Threading issues can usually be avoided in typical UI code that makes correct use of async patterns and background worker threads. 通常,如果你定义自己的 DependencyObject 类型并尝试将这些类型用于 DependencyObject 未必适宜的数据源或其他场景,只会遇到与 DependencyObject 相关的线程处理问题。You typically only run into DependencyObject-related threading issues if you are defining your own DependencyObject types and you attempt to use them for data sources or other scenarios where a DependencyObject isn't necessarily appropriate.

概念材料Conceptual material