Condividi tramite


Attached Properties Overview

An attached property is a concept defined by Extensible Application Markup Language (XAML). An attached property is intended to be used as a type of global property that is settable on any object. In Windows Presentation Foundation (WPF), attached properties are typically defined as a specialized form of dependency property that does not have the conventional property "wrapper".

This topic contains the following sections.

  • Prerequisites
  • Why Use Attached Properties
  • Attached Properties in XAML
  • How Attached Properties are Used by the Owning Type
  • Attached Properties in Code
  • Attached Property Metadata
  • When to Create an Attached Property
  • How to Create an Attached Property
  • Learning More About Attached Properties
  • Related Topics

Prerequisites

This topic assumes that you understand dependency properties from the perspective of a consumer of existing dependency properties on Windows Presentation Foundation (WPF) classes, and have read the Dependency Properties Overview. To follow the examples in this topic, you should also understand Extensible Application Markup Language (XAML) and know how to write WPF applications.

Why Use Attached Properties

One purpose of an attached property is to allow different child elements to specify unique values for a property that is actually defined in a parent element. A specific application of this scenario is having child elements inform the parent how they wish to be presented in the user interface (UI). One example is the System.Windows.Controls.DockPanel.Dock property. The System.Windows.Controls.DockPanel.Dock property is created as an attached property because it is designed to be set on elements that are contained within a DockPanel, rather than on DockPanel itself. The DockPanel class defines the static DependencyProperty field named DockProperty, and then provides the GetDock and SetDock methods as public accessors for the attached property.

Attached Properties in XAML

In XAML, you set attached properties by using the syntax AttachedPropertyProvider.PropertyName

The following is an example of how you can set System.Windows.Controls.DockPanel.Dock in XAML:

<DockPanel>
  <CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>

Note that the usage is somewhat similar to a static property; you always reference the type DockPanel that owns and registers the attached property, rather than referring to any instance specified by name.

Also, because an attached property in XAML is an attribute that you set in markup, only the set operation has any relevance. You cannot directly get a property in XAML, although there are some indirect mechanisms for comparing values, such as triggers in styles (for details, see Styling and Templating).

Attached Property Implementation in WPF

In Windows Presentation Foundation (WPF), most of the attached properties that exist on WPF types are implemented as dependency properties. Attached properties are a XAML concept, whereas dependency properties are a WPF concept. Because WPF attached properties are dependency properties, they support some dependency property concepts such as metadata, but some other dependency property concepts are not supported. For instance, attached properties cannot inherit values.

How Attached Properties are Used by the Owning Type

Although attached properties are settable on any object, that does not automatically mean that setting the property will produce a tangible result, or that the value will ever be read. Generally, attached properties are intended so that objects coming from a wide variety of possible class hierarchies or logical relationships can each report common information to the owning type. The type that defines the attached property typically follows one of these models:

  • The type that defines the attached property is designed so that it can be the parent element of the elements that will set values for the attached property. The type then iterates its child elements through internal logic, obtains the values, and acts on those values in some manner.

  • The type that defines the attached property will be used as the child element for a variety of possible parent elements and content models.

  • The type that defines the attached property represents a service. Other types set values for the attached property. Then, when the element that set the property is evaluated in the context of the service, the attached property values are obtained through internal logic of the service class.

An Example of a Parent Element Defined Attached Property

The most typical scenario where WPF defines an attached property is when a parent element supports a child element collection, and also implements a behavior where the specifics of the behavior are reported individually for each child element.

DockPanel defines the System.Windows.Controls.DockPanel.Dock attached property, and DockPanel has class-level code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride). A DockPanel instance will always check to see whether any of its immediate child elements have set a value for . If so, those values become input for the rendering logic applied to that particular child element. Nested DockPanel instances each treat their own immediate child element collections, but that behavior is implementation-specific. It is theoretically possible to have attached properties that are handled by all parent elements even in nested cases, or to handle for child elements that are not in the immediate child element collection. If the System.Windows.Controls.DockPanel attached property is set on an element that has no DockPanel parent element to act upon it, no error or exception is raised. This simply means that a global property value was set, but it has no current DockPanel parent that could consume the information.

Attached Properties in Code

Attached properties in WPF do not have the typical CLR "wrapper" methods for easy get/set access. This is because the attached property is not necessarily part of the CLR namespace for instances where the property is set. However, a XAML reader be able to set those values when XAML is processed. To be an effective attached property, the owner type of the attached property must implement dedicated accessor methods in the form Get[PropertyName] and Set[PropertyName]. These dedicated accessor methods are also how you must get or set the attached property in code.

The following example shows how you can set an attached property in code. In this example, myCheckBox is an instance of the CheckBox class.

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);

Similar to the XAML case, if myCheckBox had not already been added as a child element of myDockPanel by the third line of code, the fourth line of code would not raise an exception, but the property value would not interact with a DockPanel parent and thus would do nothing. Only a System.Windows.Controls.DockPanel.Dock value set on a child element combined with the presence of a DockPanel parent element will cause an effective behavior in the rendered application.

Attached Property Metadata

When registering the property, FrameworkPropertyMetadata is set to specify characteristics of the property, such as whether the property affects rendering, measurement, and so on. Metadata for an attached property is generally no different than on a dependency property with the exception that property inheritance on an attached property is not supported.

When to Create an Attached Property

You might create an attached property when there is a reason to have a property setting mechanism available for classes other than the defining class. The most common scenario for this is layout. Examples of existing layout properties are System.Windows.Controls.DockPanel.Dock, System.Windows.Controls.Panel.ZIndex, and System.Windows.Controls.Canvas.Top. The scenario enabled here is that elements that exist as child elements to layout-controlling elements are able to express layout requirements to their layout parent elements individually, each setting a property value that the parent defined as an attached property.

Another scenario for using an attached property is when your class represents a service, and you want classes to be able to integrate the service more transparently.

How to Create an Attached Property

If your class is defining the attached property strictly for use on other types, then the class does not have to derive from DependencyObject. But you do need to derive from DependencyObject if you follow the overall WPF model of having your attached property also be a dependency property.

Define your attached property as a dependency property by declaring a public static field of type DependencyProperty. You define this field by using the return value of the RegisterAttached method. The field name must match the attached property name, appended with the string Property, to follow the established WPF pattern of naming the identifying fields versus the properties that they represent. The attached property provider must also provide static Get[PropertyName] and Set[PropertyName] methods as accessors for the attached property; failing to do this will result in the property system being unable to use your attached property.

The Get Accessor

The signature for the Get[PropertyName] accessor must be:

public static object Get PropertyName (object target )

  • The target object can be specified as a more specific type in your implementation. For example, the System.Windows.Controls.DockPanel.GetDock(System.Windows.UIElement) method types the parameter as UIElement, because the attached property is only intended to be set on UIElement instances.

  • The return value can be specified as a more specific type in your implementation. For example, the GetDock method types it as Dock, because the value can only be set to that enumeration.

The Set Accessor

The signature for the Set[PropertyName] accessor must be:

public static void Set PropertyName (object target , object value )

  • The target object can be specified as a more specific type in your implementation. For example, the SetDock method types it as UIElement, because the attached property is only intended to be set on UIElement instances.

  • The value object can be specified as a more specific type in your implementation. For example, the SetDock method types it as Dock, because the value can only be set to that enumeration. Remember that the value for this method is the input coming from the XAML loader when it encounters your attached property in an attached property usage in markup. That input is the value specified as a XAML attribute value in markup. Therefore there must be type conversion, value serializer, or markup extension support for the type you use, such that the appropriate type can be created from the attribute value (which is ultimately just a string).

The following example shows the dependency property registration (using the RegisterAttached method), as well as the Get[PropertyName] and Set[PropertyName] accessors. In the example, the attached property name is IsBubbleSource. Therefore, the accessors must be named GetIsBubbleSource and SetIsBubbleSource.

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}

Learning More About Attached Properties

  • For more information on creating an attached property, see How to: Register an Attached Property.

  • For more advanced usage scenarios for dependency properties and attached properties, see Custom Dependency Properties.

  • You can also register the property as an attached property, and as a dependency property, but then still expose "wrapper" implementations. In this case, the property can be set either on that element, or on any element through the XAML attached property syntax.

See Also

Reference

DependencyProperty

Concepts

Dependency Properties Overview
Custom Dependency Properties