Charles Petzold

Dynamic Resources

March 16, 2006
New York City

Have you ever felt as if you finally understood something down cold, and you started coding with such supreme confidence and blissful self-assuredness that you felt as if you were striding over miles of terrain with each keystroke towards a succinct and elegant summation of everything you know?

And then when it doesn't work, you feel as if those confident strides took you right off the edge of a cliff?

Has this ever happened to you?

The subject is dynamic resources, the primary purpose of which seems to be to automatically reflect changes in system colors, fonts, and other parameters in your application. Anything more sophisticated than that probably requires data binding.

Here's some XAML that works, which I guess means that it does what I want it to do. You can download or run it here.

If you run this program in XAML Cruncher or XamlPad or IE, and you change system colors via the Control Panel, the colors displayed by this program also change. That's what I want it to do.

Towards the top of the file, the StackPanel gets a Background property of SystemColors.InactiveCaptionBrush. That's the well-documented syntax for defining a DynamicResource based on the SystemColors.InactiveCaptionBrushKey property so that the key is retained rather than the brush itself, and the background color of the StackPanel changes whenever the system colors change. No problem.

Following that is a Resources section for the StackPanel. I define a LinearGradientBrush and a SolidColorBrush, both of which use colors from SystemColors. Once again, the Key properties are used in DynamicResource elements so that the brushes change when the system color changes.

Towards the end of the file, a Label control uses the two brushes defined as resources to color its background and foreground. And here's the part that stumped me: I originally used DynamicResource for these two Label attributes, and it didn't work! The program was unresponsive to changes in system colors. It was only when I changed these two attributes to StaticResource that the Label brushes changed when the system colors changed.

This baffled me, and I had to convince myself why using StaticResource for these attributes made the brushes dynamic while DynamicResource made them static. Here's what I came up with:

When the system colors changes, the two brushes I've defined as resources are not recreated. Instead, the new colors simply replace the previous colors in the GradientStops collection of the LinearGradientBrush and the Color property of the SolidColorBrush. Same object, different colors.

Why does StaticResource work here? Because after the system colors change, the Label simply redraws itself normally using the existing foreground and background brushes. These brushes have changed since they were last used because the colors that made up the brushes were defined as dynamic resources.

Why doesn't DynamicResource work here? This is the tough one. Could it be that redrawing logic is skipped if the brush referenced by the key is the same object (which it will be in this case) even if the brush properties have changed? That's the only thing that makes sense to me (but it doesn't make that much sense to me).