Using user-selected colors and fonts

Sometimes it's useful to use one of the selected colors or fonts the user has chosen in the Windows Control Panel Personalization applet (or the older Display Settings in Windows XP), such as Window caption, Desktop color, and Selection color. Furthermore, an application may want to react dynamically to changes in those values. This can be achieved by accessing special resource keys within the SystemColors and SystemFonts classes.

Getting ready

Make sure Visual Studio is up and running. Go to the Control Panel Personalization applet and change the theme to Classic. This will make it easy to see the dynamic changes when colors of fonts change.

How to do it...

We'll create an application that uses some user-selected color and font, and reacts automaticaly to changes in those:

  1. Create a new WPF Application named CH02.UserSelectedColorsFonts.
  2. Open MainWindow.xaml. Add two rows to the grid.
  3. Add a Rectangle covering the first row and a TextBlock in the lower row. The entire markup should look as follows:
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Rectangle Margin="10" />
            <TextBlock Grid.Row="1" 
                    Text="Hello from Active Caption Font" 
            />
        </Grid>
  4. We want the rectangle filled with the color of the desktop as selected by the user in Control Panel. Add the following markup for the Fill rectangle property:
    Fill="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}"
  5. The fill color should turn to the one set in Control Panel | Personalization. Now let's set the font family and font size to those for the window caption as defined in Control Panel. Add the following markup within the TextBlock:
    FontFamily="{DynamicResource {x:Static SystemFonts.CaptionFontFamilyKey}}" 
    FontSize="{DynamicResource {x:Static SystemFonts.CaptionFontSizeKey}}"/>
  6. Run the application. This is how it may look (yours may be different depending on the settings in Control Panel):
    How to do it...
  7. Let's check if this is, in fact, dynamic. Open Control Panel and find the Personalization applet (you may need to show all control panel items before you can locate it):
    How to do it...
  8. Select Window Color at the bottom of the window:
    How to do it...
  9. Change the desktop color to something else, and click on Apply:
    How to do it...
  10. Note the rectangle fill is immediately updated without the eed to restart the application:
    How to do it...

How it works...

The resource key supplied as part of an entry in a ResourceDictionary need not be a string. In fact, it's typed as an object. The following piece of XAML indicates that the key to a DynamicResource is a static property named SystemColors.DesktopBrushKey:

Fill="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}"

Looking at this property reveals it's type as ResourceKey, which is an abstract class, so this must be something that derives from it (the exact type is not important, it's internal to the PresentationFramework assembly).

This means that this key object can do whatever is necessary behind the scenes, to be notified of changes in the system colors and reflect those changes back through the standard way when using a DynamicResource.

The font properties use the same idea. There are static properties ending with "Key" for every setting the user can change via the Personalization dialog. A similar class, SystemParameters, contains a bunch of other general properties (with a "Key" suffix), that may be changed (some via the Personalization dialog, some with code only). An example is SystemParameters.CaptionHeightKey, which indicates the current standard height of a caption of a window. This can help (for example) when constructing our own window "template" (meaning it doesn't have to look like a standard window); we may want to use some of these key properties to make our window unique on the one hand, but still have consistent (for example) caption height. We'll see an example of that in Chapter 5, Application and Windows.

There's more...

The aforementioned classes, SystemColors, SystemFonts, and SystemParameters expose the current values of the various properties as regular static properties. This means we could have used the following line to get the current brush color of the desktop:

Fill="{x:Static SystemColors.DesktopBrush}"

Although this is much simpler, and appears to work, it is not dynamic. This means the value is read at runtime, when the XAML is parsed (typically, when the window is constructed), but will remain with that value until that window is recreated (typically, when the application is restarted).

The advantage of this scheme (apart from its simplicity) is that it's lighter; WPF does not have to monitor that color for changes. This may suffice in scenarios when immediate response to colors/fonts/metrics changes is not necessary (and is probably unlikely to happen anyway).