Attached Properties

Download Sample Download the sample

Attached properties enable an object to assign a value for a property that its own class doesn't define. For example, child elements can use attached properties to inform their parent element of how they are to be presented in the user interface. The Grid control allows the row and column of a child to be specified by setting the Grid.Row and Grid.Column attached properties. Grid.Row and Grid.Column are attached properties because they are set on elements that are children of a Grid, rather than on the Grid itself.

Bindable properties should be implemented as attached properties in the following scenarios:

  • When there's a need to have a property setting mechanism available for classes other than the defining class.
  • When the class represents a service that needs to be easily integrated with other classes.

For more information about bindable properties, see Bindable Properties.

Create an attached property

The process for creating an attached property is as follows:

  1. Create a BindableProperty instance with one of the CreateAttached method overloads.
  2. Provide static GetPropertyName and SetPropertyName methods as accessors for the attached property.

Create a property

When creating an attached property for use on other types, the class where the property is created does not have to derive from BindableObject. However, the target property for accessors should be of, or derive from, BindableObject.

An attached property can be created by declaring a public static readonly property of type BindableProperty. The bindable property should be set to the returned value of one of the BindableProperty.CreateAttached method overloads. The declaration should be within the body of the owning class, but outside of any member definitions.

Important

The naming convention for attached properties is that the attached property identifier must match the property name specified in the CreateAttached method, with "Property" appended to it.

The following code shows an example of an attached property:

public static readonly BindableProperty HasShadowProperty =
  BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false);

This creates an attached property named HasShadowProperty, of type bool. The property is owned by the ShadowEffect class, and has a default value of false.

For more information about creating bindable properties, including parameters that can be specified during creation, see Create a bindable property.

Create accessors

Static GetPropertyName and SetPropertyName methods are required as accessors for the attached property, otherwise the property system will be unable to use the attached property. The GetPropertyName accessor should conform to the following signature:

public static valueType GetPropertyName(BindableObject target)

The GetPropertyName accessor should return the value that's contained in the corresponding BindableProperty field for the attached property. This can be achieved by calling the GetValue method, passing in the bindable property identifier on which to get the value, and then casting the resulting value to the required type.

The SetPropertyName accessor should conform to the following signature:

public static void SetPropertyName(BindableObject target, valueType value)

The SetPropertyName accessor should set the value of the corresponding BindableProperty field for the attached property. This can be achieved by calling the SetValue method, passing in the bindable property identifier on which to set the value, and the value to set.

For both accessors, the target object should be of, or derive from, BindableObject.

The following code example shows accessors for the HasShadow attached property:

public static bool GetHasShadow (BindableObject view)
{
  return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)
{
  view.SetValue (HasShadowProperty, value);
}

Consume an attached property

Once an attached property has been created, it can be consumed from XAML or code. In XAML, this is achieved by declaring a namespace with a prefix, with the namespace declaration indicating the Common Language Runtime (CLR) namespace name, and optionally an assembly name. For more information, see XAML Namespaces.

The following code example demonstrates a XAML namespace for a custom type that contains an attached property, which is defined within the same assembly as the application code that's referencing the custom type:

<ContentPage ... xmlns:local="clr-namespace:EffectsDemo" ...>
  ...
</ContentPage>

The namespace declaration is then used when setting the attached property on a specific control, as demonstrated in the following XAML code example:

<Label Text="Label Shadow Effect" local:ShadowEffect.HasShadow="true" />

The equivalent C# code is shown in the following code example:

var label = new Label { Text = "Label Shadow Effect" };
ShadowEffect.SetHasShadow (label, true);

Consume an attached property with a style

Attached properties can also be added to a control by a style. The following XAML code example shows an explicit style that uses the HasShadow attached property, that can be applied to Label controls:

<Style x:Key="ShadowEffectStyle" TargetType="Label">
  <Style.Setters>
    <Setter Property="local:ShadowEffect.HasShadow" Value="true" />
  </Style.Setters>
</Style>

The Style can be applied to a Label by setting its Style property to the Style instance using the StaticResource markup extension, as demonstrated in the following code example:

<Label Text="Label Shadow Effect" Style="{StaticResource ShadowEffectStyle}" />

For more information about styles, see Styles.

Advanced scenarios

When creating an attached property, there are a number of optional parameters that can be set to enable advanced attached property scenarios. This includes detecting property changes, validating property values, and coercing property values. For more information, see Advanced scenarios.