Dependency properties overview (Windows Store apps using C#/VB/C++ and XAML)

2 out of 12 rated this helpful - Rate this topic

This topic explains the dependency property system that is available when you write a Windows Store app built for Windows 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 that is tracked by a dedicated property system that is part of the Windows Runtime. 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). Many of the types you use for a Windows Store app with XAML for UI and C#, Microsoft Visual Basic or C++ will be a DependencyObject subclass, and will support dependency properties.

The purpose of dependency properties is to provide a systemic way to compute the value of a property based on other inputs. 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

A dependency property represents or supports a specific feature of the programming model for defining a Windows Store app with XAML for UI and C#, Visual Basic or C++ for code. These features include:

  • Data binding
  • Styles
  • Storyboarded animations
  • "PropertyChanged" behavior (a dependency property can be implemented to provide callbacks that can propagate changes to other dependency properties)
  • Default value through metadata
  • General property system utility such as ClearValue and metadata lookup

Dependency properties and Windows Runtime properties

Dependency properties extend basic Windows Runtime property functionality by providing a property store that backs a property. This is an alternative to the standard pattern of backing a property with a private field. You can think of a property store as being a set of property identifiers and values that exist for any particular object. Rather than being identified by name, each property in the store is a identified by a DependencyProperty instance.

The other important type that defines the dependency property system is DependencyObject. DependencyObject defines the base class that can register and own a dependency property, and it is DependencyObject that maintains its dependency property values in a store.

Here is a summation of the terminology that is used in this documentation when discussing dependency properties:

TermDescription

Dependency property

A property that exists on a DependencyObject subclass, is stored by the DependencyObject property store, and is identified by a DependencyProperty identifier. Usually the identifier is available as a static member of the defining DependencyObject.

Dependency property identifier

A DependencyProperty instance. In the case of an existing dependency property in the core API, this instance is usually exposed as a public static read-only property, as a member of the same DependencyObject type that uses the dependency property. The dependency property identifier can also be used as a parameter in APIs such as GetValue and SetValue that expose the fundamentals of the dependency property system, or Setter.Property.

Property wrapper

The callable get and set implementations for a Windows Runtime property. Or, the language-specific projection of the original definition. A get property wrapper implementation calls GetValue, passing the relevant dependency property identifier as input and returning the value. A set property wrapper implementation calls SetValue, passing the relevant dependency property identifier as one input and the value to set as the second input.

 

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.

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.


public static readonly DependencyProperty IsSpinningProperty = 
    DependencyProperty.Register(
        "IsSpinning", typeof(Boolean),
        typeof(ExampleClass), null
    );
public bool IsSpinning //the property wrapper
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

Note  The preceding example is not intended as the complete example for how to create a custom dependency property. It is intended to help illustrate dependency property concepts for anyone that learns a concept best by looking at representative code. For a more complete example of creating a custom dependency property, see Custom dependency properties.

Property functionality provided by a dependency property

Data binding

So long as the dependency property to set is on a DependencyObject subclass, a dependency property can have its value set through data binding. Data binding uses a specific markup extension syntax in XAML, or the Binding class in code. With data binding, the final property value determination is deferred until run time, and then the value is obtained from a data source. It is the deferral aspect that requires that the target property must be a dependency property.

The following example sets the text for a text block, 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 with XAML.)


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

You can also establish bindings using code rather than XAML. See SetBinding.

Note  Bindings are treated as a local value for purposes of dependency property value precedence. If you set another local value to a property that originally held a Binding value, you will eliminate the binding.

Binding sources, binding targets

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. However, to be the target of a binding, that property must be a dependency property.

If you are setting bindings in code, note that the SetBinding API is defined only for FrameworkElement. However, you can create a binding definition using BindingOperations instead, and thus reference any DependencyObject property.

For either code or XAML, remember that DataContext is a FrameworkElement property. By 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, even if the child object (which has the target property) is not a FrameworkElement and therefore does not hold its own DataContext value. However, that parent element must be a FrameworkElement in order to set and hold the DataContext. Alternatively, you must define the binding such that it can function with a null DataContext.

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. For custom binding sources, this means that the property must support INotifyPropertyChanged. Collections should support INotifyCollectionChanged. Certain classes support one of these interfaces in their implementations so that they are useful as base classes for data binding scenarios; an example of such a class is ObservableVector. For more information on data binding and how data binding relates to the property system, see Data binding overview.

Note  C++ data sources use different interfaces for change notification, see Binding to collections.

Styles and templates

Styles and templates are two of the scenarios for properties being defined as dependency properties. Styles are useful for setting properties that define the app's UI. 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. 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. For more info on styles, and some example XAML that defines a Style and uses setters, see Quickstart: styling controls.

Values that come from styles or templates are necessarily deferred. This is so that control users can re-template controls or redefine styles. And that's why styles set dependency properties.

Storyboarded animations

You can animate a dependency property's value using a storyboarded animation. Storyboarded animations in the Windows Runtime are not merely visual decorations. You can think of animations as being a state machine technique whereby you can set the state of individual properties or of whole controls, and change the value over time.

To be animated, the animation's target property must be a dependency property. Also, to be animated, the target property's value type must be supported by one of the existing Timeline-derived animation types. 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. 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.

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. For more info on VisualStateManager, see Storyboarded animations for visual states or Quickstart: 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. 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.

Default value and ClearValue

A dependency property can have a default value defined as part of its property metadata. The difference between the default value of a regular property and of a dependency property is that the default value might apply 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 template or an animation from a property, but want the value to be a reasonable default after you do so. The dependency property default value provides this value, without that value needing to be specifically set in all cases.

But you do need to deliberately set a property to the default value if you have already set it to a local value. Setting the property again just sets the local value again and does not really restore the default. 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, you call ClearValue on the property.

Dependency property value precedence

When you get the value of a dependency property, you are obtaining a value that was set on that property through any one of the inputs that participate in the Windows Runtime property system. Dependency property value precedence exists so that a variety of scenarios for how Windows Runtime properties obtain their values can interact in a predictable way.

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 some property-specific aspect of the control versus the common template, such as giving it a different background color or a different text string as content. The Windows Runtime property system uses local values at higher precedence than values provided by styles and templates, thus enabling the scenario.

Dependency property precedence list

The following is the definitive order that the property system uses when assigning the run-time values of dependency properties. Highest precedence is listed first. Further explanation of some of the precedence items can be found in subsections immediately following the list.

  1. Active animations, visual state animations, or animations with a HoldEnd behavior. To have any practical effect, an animation of a property must have precedence over the base (unanimated) value, even if that value was set locally.
  2. 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. Templated properties. An element has these if it was created as part of a template (a ControlTemplate or DataTemplate).
  4. Style setters. Values from a Setter within styles from page or application resources.
  5. Default value. Any dependency property can have a default value.

Templated properties

Templated properties as a precedence item do not apply to any property of an element that you declare directly in XAML page markup. The templated property concept exists only for objects within an object tree that come into existence through the application of the template. When the property system searches the templated properties for a value, it is searching the template that created that object. The property values from the template act as if they were set as a local value on the object, but must be distinguishable from a true local value.

Note that depending on how the template is constructed, the template might override even local values, if the template failed to provide TemplateBinding references for relevant settable properties as they should appear in the template elements. This is usually done only if the property is an inherited property that does not have an analogous property in the specific template and visual design.

Bindings and precedence

Binding operations are treated as if they were setting the value to which they are being applied. For example, a binding applied to a local value acts as local value, and a binding for a property setter within a style applies as a style setter does. Because bindings must be able to obtain values from the run-time state of the application, the actual 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, but with a value that is deferred. If you have a binding in place for a property value, any local value that you set subsequently replaces the binding entirely. Similarly, if you call SetBinding, you replace the previous local value.

Storyboarded animations and base value

Storyboarded animations act on a value that is termed as the "base value" throughout this documentation. The base value is thus whatever value is determined through evaluating upwards in the precedence until "local value" is reached.

For an animated property, the base value can have an effect on the animated value, if that animation does not specify both From and To for certain behaviors, or if the animation deliberately reverts to the base value when completed. Afterwards, normal precedence is used for the base value determination.

Conversely, 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.

Multiple animations might be applied to a single property, with each of these animations possibly having been defined from different points in the value precedence. However, these animations will potentially composite their values, rather than just applying the animation from the higher precedence. This depends on exactly how the animations are defined, and the type of the value that is being animated.

Default values

Default values for dependency properties are generally one of the following:

  • A reference-type dependency property default value is null.
  • A value-type dependency property default value is the default-constructed value. For primitives, this leads to expected defaults such as 0 for int and double. For structures such as Point or custom structures, this uses the implicit default constructor. For enumerations, the default is the first defined member.
  • A string-type dependency property default value is an empty string.

DependencyObject and threading

All DependencyObject instances must be created on the UI thread which is associated with the current Window that is shown by a Windows Store app built for Windows using C++, C#, or Visual Basic. Although each DependencyObject must be created on the main UI thread, the objects can be accessed using a dispatcher reference from other threads, by calling Dispatcher.

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. Threading issues can usually be avoided in typical UI code that makes correct use of async patterns and background worker threads. 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.

Related topics

Conceptual material
Custom dependency properties
Attached properties overview
Data binding overview
Storyboarded animations
Creating Windows Runtime components
XAML user and custom controls sample
APIs related to dependency properties
DependencyObject
DependencyProperty

 

 

Build date: 11/28/2012

Did you find this helpful?
(1500 characters remaining)
© 2013 Microsoft. All rights reserved.