Charles Petzold

Flexibility with Property Elements

January 15, 2007
New York, NY

Quite by accident, I discovered something interesting about XAML property elements that I did not know, and which might be useful in some special circumstances.

Normally you need a property element when you can't set an attribute to a simple string. For example, in this (complete) XAML file, Button.Foreground is broken out from the Button tag as a property element because it needs to be set to a LinearGradientBrush, and that requires additional markup:

What I discovered is that instead of Button.Foreground you can use any class that Button derives from that has a Foreground property, for example:

And this will also work:

What's interesting as well is that you can use TextBlock as the class in the property element:

If you look at the class documentation, it seems like both Control and TextBlock independently define their own Foreground properties. But they're not actually as independent as they may seem. If you use the handy ExploreDependencyProperties program from Chapter 16 of Applications = Code + Markup, you'll find that the Foreground dependency property is registered by TextElement, and that's the class that owns the property. Sure enough, you can use TextElement as the class:

In general, it seems like you can use any ancestral class up to the class that defines the property, or you can use the class that registered the dependency property. The use of TextBlock.Foreground seems like an anomaly here, because TextBlock falls into either of those categories. (Moreover, with a TextBlock element, you can't use Control.Foreground as a property element.) I suspect that TextBlock is allowed because the Button is using a TextBlock to display the button's text.

Where might exploiting this be useful? Perhaps if you're creating some XAML snippets for pasting into code, it might help if you didn't need to match the class name exactly. Also, if you're changing an element from one class to a derivative class, you only need to change the start and end tags, and not any child property elements. (That's how I discovered this.)