Attached properties

Attached properties were probably the very first technology we invented for WPF. Back in late 2000, before WPF/avalon even existed, Jeff Bogdan and I were doing some prototyping, and we ran into a problem -- every layout had a set of properties that it wanted on the elements it's laying out. DockPanel wants each child element to have a Dock property, GridPanel wants each child to have Row & Column, etc.. But we wanted an extensible set of layouts, so we couldn't just add all these properties to the base class (then called Control I believe). We considered a couple other models. Scripting languages allow you to create arbitrary properties at any time, with the downside that if you make a typo, you get a new property you never intended. That wasn't cool... We also looked at Windows Forms' concept of extender providers:

SomeProvider provider = new SomeProvider();

provider.SetDock(button, Dock.Fill);

This had the strong typing we were looking for, but there was a lifetime management issue. Because the data storage was part of the extender provider, rather than the target element, they really didn't work very well with styles (when do you dispose of the extender provider? After the last style usage is gone? Way too much work to track!). So we invented the notion of attached properties, and convinced Mark Finnocchio to embed this concept deeply into the fledgling property engine.

These days, there's almost two completely different ways to look at attached properties. From the property engine perspective, all properties are potentially attachable (although as an optimization, some classes provide built-in storage for particular properties). But from a parser perspective, those "CLR wrappers" make a big difference.  The property engine couldn't care less whether you wrote

int Dock { get; set; }

or

 int GetDock(DependencyObject o);
void SetDock(DependencyObject o, int value);

Or even didn't write them at all and asked people to use SetValue(DockProperty).  But the parser cares -- it won't let you use attached property syntax for non-attached properties. Because the parser tries not to understand dependency properties, it would rather just set Dock or call SetDock, not deal with some funny SetValue thing. As, for that matter, would most users.

But from a property engine perspective, there's really just attached properties. You can call panel.SetValue(CheckBox.CheckedProperty, true), and property engine will happily set that attached property to true. Doesn't matter that nobody is ever going to try to read that property value (setting a property doesn't mean someone cares), doesn't matter that the author of CheckBox probably never intended this, you're free to do it.

That's worth repeating -- in the typical layout example:

 <DockPanel>
    <Button DockPanel.Dock="top"/>
</DockPanel>

From a property engine perspective, it's irrelevant that Button happens to be inside a DockPanel perspective. You could set DockPanel.Dock even if your parent is a Grid -- that property won't do any good, because Grid doesn't look at the DockPanel.Dock property, but you can do it.

One of the other more obscure things about attached properties is that DependencyProperty.Register() and RegisterAttached() aren't actually all that different. Both create properties that are capable of being attached, the only difference is that Register() associates the property metadata with the type you actually care about (e.g., CheckBox for the Checked property), whereas RegisterAttached applies the property metadata to all DependencyObjects.  We do this mostly so when controls like CheckBox include an invalidation callback, inside that callback they are free to cast the DO to a CheckBox, because with the metadata registered where it is, the property engine won't call them if someone does panel.SetValue(CheckBox.CheckedProperty, true).