WPF's Mysterious Attached Property Shadow Accessors

After learning the fundamentals of WPF, one will inevitably come across the XAML concept of attached properties. They allow for extra properties to be set on as well as additional functionality be provided by any XAML element, all while being separate from said element’s own object model.

Although the design and use of attached properties is one of the more advanced topics for a WPF neophyte to grapple with, the boons that they offer will quickly become apparent to anyone who delves in to the matter.

So, that being said, anyone fairly proficient with WPF will be familiar with both the attached properties built-in to the framework as well as how and when they can create their own attached properties in order to realize a solution for whatever problem they’re facing.

But even if you’ve had a lot of dealings with attached properties, there’s a good chance you’re not fully cognizant of some of the lesser-known aspects of how WPF’s attached properties actually work, especially in regards to the some of the most prominent of the several required actions we need to take in order to make them work.

I’m speaking of the required static Get and Set accessors we’re told that we have to implement in order for an attached property to be treated as…an attached property! We’ll be looking at some nuances with this particular requirement oddity as well as what “shadow accessors” are, and how we can use them to get some more expressiveness out of our code and, in particular, our XAML.

Thou Shalt Have Static Get/Set Accessors, or Else

There’s a number of things one must do in order to create a new attached property, the most obvious of them being the need to register a static object (which will heretofore become the attached property) with the DependencyProperty.RegisterAttached method.

But, as anyone who has made a few attached properties knows, we’re required to provide static Get and Set accessors that get and set the attached property from and to a supplied DependencyObject respectively.

This is an awkward requirement, to be sure, as given that the code elements are static, there’s no nice, object-oriented way to enforce their implementation. If you’ve made an attached property before, you probably know this requirement well because, due to reasons I’ve just stated, you probably forgot to implement these required accessors on more than one occasion.

What happens if you don’t provide these accessors? Well, you get errors. Your use of the attached property in XAML will probably be flagged as an error, because what you’re trying to use isn’t a valid attached property.

You have to supply those accessors.

Some Example Get/Set Accessors for Your Soul

Let’s take a quick look at an example of these required Get and Set accessors with some code:

/// <summary>
/// Provides your soul.
/// </summary>
public static class Soul
{
    /// <summary>
    /// Identifies the attached property that serves as an example for this article.
    /// </summary>
    public static readonly DependencyProperty ExampleProperty
        = DependencyProperty.RegisterAttached("Example",
                                              typeof(int),
                                              typeof(Soul));
    /// <summary>
    /// Gets the value of the <see cref="ExampleProperty"/> attached property for a given
    /// <see cref="DependencyObject"/>.
    /// </summary>
    /// <param name="source">The dependency object from which the property value is read.</param>
    /// <returns>The example value for <c>source</c>.</returns>
    public static int GetExample(DependencyObject source)
    {
        Require.NotNull(source, nameof(source));

        return (int) source.GetValue(ExampleProperty);
    }

    /// <summary>
    /// Sets the value of the <see cref="ExampleProperty"/> attached property on a given
    /// <see cref="DependencyObject"/>.
    /// </summary>
    /// <param name="source">
    /// The dependency object to which the attached property is written.
    /// </param>
    /// <param name="value">The example value to set.</param>
    public static void SetExample(DependencyObject source, int value)
    {
        Require.NotNull(source, nameof(source));

        source.SetValue(ExampleProperty, value);
    }
}

Shown above is a very simple attached property that can be used on any DependencyObject, and is able to be assigned an integer value. Other than that, it doesn’t do anything else really, and that’s fine as this is just an example.

As you can see, the static accessors don’t really do anything too fancy, they’re just getting or setting the value on a given DependencyObject instance. We need to have them there, or otherwise we’re going to see red squiggly lines show up as we’re typing any XAML that’s using said attached properties in Visual Studio.

The Required Get/Set Accessors’ Dirty Little Secret

As I’ve stated earlier, attached properties are supposed to feature public accessors in the form of GetNameOfProperty and SetNameOfProperty. Note that NameOfProperty must be the name of the property as it would be referenced from XAML; so, although our attached property’s name in code is ExampleProperty, we want the accessors to be named GetExample and SetExample since we’ll be referencing our attached property in XAML like so:

<TextBlock fenestra:Soul.Example="{Binding SomeNumber}" />

Fenestra is the name of the Bad Echo technologies WPF UI framework, so assume we added our “Soul” to that namespace.

We can also see the name we need to use reflected in the first parameter passed to DependencyProperty.RegisterAttached. Normally, we can make use of a nameof expression here; however, as was stated earlier, attached properties are not part of a DependencyObject‘s object model, so there is no instance property to feed into the expression.

However, I happen to have a nice class, part of the Fenestra framework, that will return an appropriate name based on the name of the attached property’s static object, and which I use in my own code:

NameOf.ReadDependencyPropertyName(() => ExampleProperty))

Alright. Let’s get back to the topic on hand with the accessors:

These accessors are commonly described, by Microsoft as well as others, as being absolute requirements for the complete and proper functioning of an attached property.

One might assume, given that these accessors are described as essential, that any declarations of a particular attached property in XAML would result in said property’s static accessors being accessed at run-time.

However, this is not the case! None of your attached properties’ accessors will ever be invoked at runtime.

All it takes to verify this is to simply place a breakpoint in one of your accessors, and see it never going off when debugging your program. Some of you have probably done this before and wondered what was going on for a bit before shrugging it off.

Why Are the Accessors Not Invoked at Run-Time?

Our accessors are never invoked at run-time purposely as an optimization by the XAML parser. The only time these accessors actually get invoked, other than the calls we are making to them in our own code (which, for most attached properties, doesn’t happen much), is at design-time by the XAML designer when data binding is occurring on the property.

So, these accessors are really more for the XAML designer than anything else.

While this “little-known fact” might come off as mere trivia, this particular optimization that we’re talking about can result in problems if the attached property has been designed such that proper operation requires invocation of an accessor prior to the property being referenced and used.

In other words, if our attached property requires some level of initialization and setup prior to its use, how can we accomplish this? As far as the initial state of a DependencyProperty goes, we’re typically constrained to only being able to specify the default value of the property via its default property metadata.

This is very limiting, and makes more complicated types of initializations, especially if they need to be instance-specific, simply not possible.

The logical place one might try to stick their initializations might be in…drumroll…the Get accessor! And, as I’ve just shown, this would unfortunately appear to not be an option.

Property Requiring Complex Initialization Example

Let’s go over a quick real-world example of an attached property that could really benefit from being able to initialize itself via its own Get accessor.

I have an attached property that, in actuality, serves as a collection of other attached properties. It is designed so its use is very intuitive in a XAML context.

<fenestra:OutlinedTextElement x:Name="Value"
                              Style="{StaticResource StatisticTextStyle}"
                              Text="{fenestra:SteppedBinding    Value,
                                                                NotifyOnTargetUpdated=True, 
                                                                SteppingDuration=00:00:02,
                                                                MinimumSteps=10,
                                                                IsInteger=True}"
                              Grid.Column="1"
                              Grid.Row="1">
    <!--Here is our attached property collection...which is also an attached property.-->
    <fenestra:TargetUpdatedEventBehavior.Actions>
        <fenestra:ConditionAction IsEnabled="{Binding IsCritical}"/>
        <fenestra:BeginStoryboardAction Storyboard="{StaticResource ExplodeTextAnimation}"/>
    </fenestra:TargetUpdatedEventBehavior.Actions>
</fenestra:OutlinedTextElement>

This particular attached property allows me to declaratively assign a bunch of special actions to go off whenever the TargetUpdated routed event fires on the target DependencyObject.

Very neat. However, this sort of thing doesn’t just work out of the box. The collection cannot have a null value by default; it needs to be initialized, otherwise we’ll get errors when the run-time tries to add items to it.

We can’t solve this simply by having an initialized instance of the collection type set in the attached property’s default PropertyMetadata, as that metadata is declared statically, and therefore all uses of the attached property would be using this same instance.

Nope, we need the collection’s initialization to be unique per every DependencyObject target wanting to use it. The only place we’re able to do that, is within the attached property’s Get accessor.

Luckily, by using a “shadow accessor”, we can accomplish our goal.

Shadow Accessors

We can circumvent the particular optimization employed by the XAML parser, where it skips the invocation of an attached property’s Get or Set accessor, by making use of a “shadow accessor”.

I don’t believe “shadow accessor” is a real term, it’s more or less something I’ve made up (so, I suppose it is at least somewhat real now that I’m putting it in writing), although I’m basing the term on some Microsoft source code where I picked up the technique.

Normally, when registering a DependencyProperty, we must always provide the name of the property as it would appear when being referenced from XAML. Multiple examples of this have been shown in this article already — it’s basically something you learn to just do when working with WPF.

Well, if we’re actually a bit naughty and register the property using a name that does not match up with how it’ll be referenced in XAML, then we actually circumvent the problematic XAML parser optimization.

I have a method in the NameOf class, a type which I referenced earlier, that does just this:

public static string ReadAccessorEnabledDependencyPropertyName<T>(Expression<Func<T>> expression)
{
    Require.NotNull(expression, nameof(expression));

    var body = (MemberExpression) expression.Body;
    string nameWithoutSuffix = RemoveDependencyPropertySuffix(body);

    return $"Shadow{nameWithoutSuffix}";
}

Although you can just simply change your attached property registration like so:

/// <summary>
/// Identifies the attached property that serves as an example for this article.
/// </summary>
public static readonly DependencyProperty ExampleProperty
    = DependencyProperty.RegisterAttached("ShadowExample",
                                          typeof(int),
                                          typeof(Soul));

And, lo and behold! Your attached property’s static accessors will now be called, allowing you to do all the complicated initialization stuff you wanted to do, such as doing what needs to be done in order to have a powerful, collection-based attached property that lets you do whatever you want to dream of. Woot!

You don’t have to prepend “Shadow” to the name per se, but…c’mon, it just reeks of intrigue my friend!

I hope this article has shed some light on this slightly mysterious aspect of an important WPF system for you. Take care!