Поделиться через


Dependency Properties Overview

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Silverlight provides a set of services that can be used to extend the functionality of a CLR property. Collectively, these services are typically referred to as the Silverlight property system. A property that is backed by the Silverlight property system is known as a dependency property. This overview describes the Silverlight property system and the capabilities of a dependency property. This overview also introduces specialized aspects of dependency properties, such as dependency property metadata, and how to create your own dependency property in a custom class.

This topic contains the following sections.

  • Prerequisites
  • Dependency Properties in Silverlight
  • Dependency Properties Back CLR Properties
  • Setting Property Values
  • Property Functionality Provided by a Dependency Property
  • Dependency Property Value Precedence
  • Learning More About Dependency Properties
  • Related Topics

Prerequisites

This topic assumes that you have some basic knowledge of the CLR and object-oriented programming. In order to follow the examples in this topic, you should also understand XAML and know how to write Silverlight-based applications.

Dependency Properties in Silverlight

In Silverlight, dependency properties are typically exposed as CLR properties also. At a basic level, you could interact with these properties directly and never know that they are implemented as a dependency property. However, you should become familiar with some or all of the features of the Silverlight property system, so that you can take advantage of the dependency property features.

The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs. These other inputs might include external properties such as user preference, just-in-time property determination mechanisms such as data binding and animations/storyboards, multiple-use templates such as resources and styles, or values known through parent-child relationships with other elements in the object tree. In addition, a dependency property can be implemented to provide callbacks that can propagate changes to other properties.

For Silverlight types that are a DependencyObject and are visible in the UI in some way, most of the settable properties on the object are dependency properties, and can therefore support animation. For FrameworkElement derived types, the dependency property also can support styling. For read-only properties, it is less likely that the property is a dependency property, although there are some read-only properties that are still implemented as dependency properties because of WPF compatibility. For the uncommon cases where a settable property on a DependencyObject is not a dependency property, that property will be unable to support animation, data binding, or FrameworkElement styling.

In the SDK reference, you can definitively identify if a given Silverlight property is implemented as a dependency property. In the Remarks section, if there is "Dependency Property Identifier Field" and a link to an API (a field) where the name ends with Property, the property is a dependency property. This same convention of exposing a field and naming it in a corresponding way should be followed by custom or third party dependency properties also. For example, if there is a property named Ticks defined by a type, and a field named TicksProperty exposed by the same type (and the field is of type DependencyProperty), then Ticks is a dependency property.

Dependency Properties Back CLR Properties

Dependency properties and the Silverlight property system extend CLR-defined property functionality by providing a property store that backs a property, as an alternative implementation to the standard pattern of backing the property with a private field. The name of the type that identifies each property in the store is DependencyProperty. The other important type that defines the Silverlight property system is DependencyObjectDependencyObject 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.

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

  • Dependency property: A property that exists on a DependencyObject, is stored by the DependencyObject property store, and is identified by a DependencyProperty identifier on the owning DependencyObject.

  • Dependency property identifier: A DependencyProperty instance. In the case of an existing dependency property in the Silverlight core API, this instance is usually exposed as a public static readonly field, as a member of the same DependencyObject type that holds the dependency property. In the case of a custom dependency property, this field is obtained as a return value when registering a dependency property. You should then store this field as a member of the class. The dependency property identifier field can also be used as a parameter in APIs such as GetValue and SetValue that expose the fundamentals of the Silverlight property system, as well as other APIs where dependency properties are specified by identifier (for instance, some signatures of the PropertyPath constructor, or Setter.Property).

  • CLR wrapper: The actual get and set implementations for the property as it is visible to the CLR type system (which operates at a lower level architecturally). These implementations incorporate the dependency property identifier by using it in the GetValue and SetValue calls, thus providing the backing for the property using the Silverlight property system. GetValue / SetValue calls should be the entirety of the get and set implementations. The wrapper is not just convenience for callers, it also exposes the dependency property to any process or tool that uses reflection or the CLR type system as its basis, which is vital in many scenarios.

The following example defines a custom IsSpinning dependency property, and shows the relationship of the DependencyProperty identifier to the property that it backs.

Public Shared ReadOnly IsSpinningProperty As DependencyProperty = _
    DependencyProperty.Register("IsSpinning", _
    GetType(Boolean), _
    GetType(SilverlightExampleClass), _
    Nothing)
Public Property IsSpinning() As Boolean
    Get
        Return CBool(GetValue(IsSpinningProperty))
    End Get
    Set(ByVal value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property
public static readonly DependencyProperty IsSpinningProperty = 
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(SilverlightExampleClass), null
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}
NoteNote:

 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 Objects and Dependency Properties.

Setting Property Values

As a broad generalization, you can set Silverlight properties either in code or in XAML. For purposes of code versus XAML distinctions, whether a property is backed by a dependency property generally does not matter. Either way, if a property is settable and you set it, a value is set to the object that holds the property in its property store, however that store is implemented. There are however properties that can only be set in code. In most cases this is because the type that the property accepts cannot be expressed in XAML. Also, certain property-related mechanisms exist that only work with dependency properties and not CLR properties in general because the mechanism uses DependencyProperty as a type; an example of this is Setter.Property, used in styles and templates.

Setting Property Values in XAML

XAML supports a variety of syntax forms for setting properties. The simplest form is as a string attribute. Which syntax to use for a particular property will depend on the type that a property uses as its value, as well as other factors such as the presence of a type converter. For more information on XAML syntax for property setting, see XAML Overview. Specific property usage syntax for XAML is typically found in the Syntax sections of reference pages and can also often be found in the Example sections.

In terms of syntax, the Silverlight XAML parser does not distinguish between standard CLR properties and those which are backed by a dependency property: each is processed as a string. However, there are several XAML-property system interactions that you should be aware of:

  • Only dependency properties can accept values that use the Binding or TemplateBinding markup extensions, because it is the property system (not the XAML parser per se) that engages to supply these values.

  • The Silverlight XAML parser bypasses the CLR wrapper whenever setting any style Setter value. For more information, see Custom Dependency Objects and Dependency Properties.

  • StaticResource Markup Extension can be used for any property being set in XAML; the property does not have to be a dependency property. However, that property does need to use a value that is shareable from out of a Silverlight resource dictionary as defined elsewhere in XAML, which is not strictly speaking a property system defined behavior. For more information, see Resource Dictionaries.

Setting Properties in Code

Setting dependency property values in code is typically just a standard CLR property usage exposed by the CLR wrapper.

scratchCanvas.Width = 200; //scratchCanvas is an existing Canvas instance
scratchCanvas.Width = 200 ' scratchCanvas is an existing Canvas instance

Getting a property value is also essentially a standard property usage:

double whatWidth = scratchCanvas.Width;
Dim whatWidth As Double
whatWidth = scratchCanvas.Width

You can also call the property system APIs GetValue and SetValue directly. This is not typically necessary if you are using existing properties (the wrappers are more convenient, and provide better exposure of the property for developer tools), but calling the property system APIs directly is appropriate for certain scenarios. This usage is representative of the fact that the actual property store for dependency objects is implemented in the DependencyObject class and is available to all instances of DependencyObject.

Properties can be also set in the initially loaded XAML and then accessed later in code, by accessing the run-time object tree by some means (event handlers in code-behind, FindName as an entry point, traversing the object tree from the root, and so on).

Property Functionality Provided by a Dependency Property

A dependency property provides functionality that extends the functionality of a property as opposed to a property that is backed by a field. Often, each such functionality represents or supports a specific feature of the overall Silverlight set of features:

  • Data binding

  • Styles

  • Animations

  • Property-changed behavior

  • Default value and ClearValue

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 works through a specific markup extension syntax in XAML, or the Binding object in code. With data binding, the final property value determination is deferred until run time, at which time the value is obtained from a data source.

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 (not shown).

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

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

NoteNote:

Bindings are treated as a local value for purposes of dependency property value precedence, which means that if you set another local value, you will eliminate the binding.

Binding Sources, Binding Targets

In order to be the source of a binding, a property does not need to be a dependency property; you can use any CLR property as a binding source. However, in order to be the target of a binding, the 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, 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.

NoteNote:

Applications targeting Silverlight 3 can only bind to target properties of a FrameworkElement. Support for binding to any DependencyObject dependency property was added in Silverlight 4.

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 CLR 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 ObservableCollection<T>.

For more information on data binding in Silverlight, and how data binding relates to the property system, see Data Binding.

Styles

Styles and templates are two of the main motivating scenarios for properties being defined as dependency properties. Styles are particularly useful for setting properties that define application user interface (UI). Styles are typically defined as resources in XAML, either as application-level or page-level resource dictionaries, or in XAML files that play a particular role in the overall Silverlight application model such as generic.xaml. Styles interact with the property system because they typically contain "setters" for particular properties. The most important property typically being set in this way is the Template of a Control, which defines most of the visual appearance and visual state for the Control.

For more information on styles and some example XAML that defines a Style and uses setters, see Style.

Animations

In order to be animated, the animation's target property must be a dependency property. Also, in order 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 is running, the animated value operates at a higher precedence than any value (such as a local value) than the property otherwise has. Animations also have an optional behavior that can cause animations to apply to property values even if the animation visually appears to be stopped, by using a HoldEnd behavior.

Animations in Silverlight are not just for the conventional usage of animation to produce one-time or repeating visual decorative elements. You can think of animations as being a state machine technique whereby you can set the state of individual properties or of whole controls based on some stimulus. This principle is embodied by the use of animations as part of the VisualStateManager state model for controls. For more information on animations, see Animation For more information on VisualStateManager, see Creating a New Control by Creating a ControlTemplate.

Property-Changed Behavior

Property-changed behavior is one of the main reasons for the "dependency" portion of the terminology for a dependency property. Maintaining valid values for a property where another property can influence the first property's value is a difficult development problem in many platforms. The Silverlight dependency property system builds in the capability for each dependency property to specify a callback that is called whenever its property value changes. This callback can be used to notify or change related property values, in a generally synchronous manner.

Many existing Silverlight dependency properties have a property-changed behavior. You can also add such behavior to custom dependency properties, and implement your own property-changed callbacks. For more information, see Example PropertyChangedCallback Implementation section of Custom Dependency Objects and Dependency Properties.

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 needing to be specifically set in all cases.

The case where you do need to deliberately set to the default value is if you have already set a local value. Setting the property again just sets the local value again and does not really restore the default. To reset the value to be the default again, and also to enable other participants in precedence that fall below the local value precedence to act again, you call ClearValue on the property.

Dependency Property Value Precedence

When you get the value of a dependency property, you are potentially obtaining a value that was set on that property through any one of the property-based inputs that participate in the Silverlight property system. Dependency property value precedence exists so that a variety of scenarios for how Silverlight 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 Silverlight property system uses local values at higher precedence than style and template provided values, thus enabling the scenario.

More information about the concept of dependency property precedence, and a listing of the order in which the precedence applies, is provided in the topic Dependency Property Value Precedence.

Learning More About Dependency Properties

  • Attached Properties Overview: An attached property is a type of property that supports a specialized XAML syntax in Silverlight. An attached property often does not have a direct correspondence with a CLR property hierarchy. The typical purpose of attached properties is to allow child elements to report property values to a parent element, even if the parent element and child element do not both possess that property as a possible member in a generalized type system. One primary scenario for attached properties in Silverlight is to enable child elements to inform the parent how they should be presented in UI; for an example of this scenario, see Canvas.Left.

  • Custom Dependency Objects and Dependency Properties: Component developers or application developers may wish to create their own dependency property, in order to enable capabilities such as data binding or style support, or for property-changed behavior.