SystemColors Reference
WPF exposes a swatch of colors that comprise the current Windows system theme. These are available in the SystemColors class as Colors, Brushes, and corresponding ResourceKeys (for binding with dynamic notification of changes to these colors, e.g. if the user switches Windows themes). This blog post contains a WPF tool to visually describe what Windows system colors are exposed through WPF and how these SystemColors members change as the Windows theme changes. Screenshots from the tool are contained in the blog post.
- SystemColors Swatch
- Reference Tables - SystemColors tables for different Windows themes
- What are the Windows system colors?
- SystemColors in WPF
- Overriding SystemColors using ResourceKeys to skin WPF controls
1. SystemColors Swatch
This graph is intended as a quick reference for control authors. While creating the default Style and template for a control, pick colors from this table that give the desired look across different OS themes. Here's a direct link you can bookmark and use as a quick reference. (Note: Luna is deprecated and is only available on XP)
2. Reference Tables - SystemColors tables for different Windows themes
Here's the source for the tool I used to create these tables, and it is also attached to the blog post. Check it out!
3. What are the Windows system colors?
Windows uses a set of colors to draw UI elements like highlight borders, text, shadows, control chrome, window frames, etc. These colors can be retrieved and set using Windows APIs like GetSysColor. WPF applications expose these colors through managed wrappers as we’ll see in the SystemColors class.
Each Windows theme specifies the system colors differently. You can tweak the system colors yourself to create your own Windows theme, and WPF is able to pick up the colors the user has set in their theme so that WPF controls render to match the current theme.
To personalize your system colors on Win7, bring up the Appearance and Personalization config either through Desktop or Control Panel:
Click on “Window Color” to customize the window glass color and other system colors:
Choose “Advanced appearance settings…”:
Here you can configure the different system colors for Windows to use. The combo box allows you to select a UI element, and the color picker enables you to assign colors and other properties for it:
If you play around with these settings, you’ll see native Windows applications and WPF applications transform by picking up on the color settings. For example, if we change the black color for “3D Objects” to purple, then the foreground of certain UI elements picks this up:
In general, don’t worry about specifics here, like which settings affect which controls. Just be aware that WPF controls bind to many of the colors and other parameters specified here. (Note: While WPF apps dynamically assume the new system colors when the Windows theme changes, the same cannot be said for tweaking individual system colors. If you are using a WPF app to calibrate changes to the Windows system colors, you should recycle the app between sets of changes.)
4. SystemColors in WPF
WPF exposes Windows system colors through the SystemColors class as static Color, Brush, and ResourceKey properties. That is, for each unique system color exposed by WPF, there is a corresponding Color, ResourceKey for the Color, SolidColorBrush, and ResourceKey for the SolidColorBrush. If you don’t care about dynamic change notification, then in your XAML you can bind to the Brush directly:
<Button Background="{x:Static SystemColors.DesktopBrush}" .../>
However, control authors using SystemColors will likely want to bind to the resource keys instead so that they receive dynamic change notification. For example, if you are retemplating Button but wanted to basically match the look of a Windows button, you could bind a template element’s Background to SystemColors.ControlBrushKey using a DynamicResource reference:
<ControlTemplate TargetType="Button">
<Grid ...>
<Border Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" ...>
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
By using the correct SystemColor (use the chart at the beginning of this blog post) in a control’s template, the control will appear more natural under the different Windows themes (and even under many custom themes). That way, instead of having to craft different templates for the different Windows themes to pick up theme-specific color settings, you achieve a theme-specific look automatically.
5. Overriding SystemColors using ResourceKeys to skin WPF controls
We’ve mentioned that stock WPF controls bind to certain SystemColors in their templates to achieve a look that matches up nicely with the current Windows theme. In some cases you may want to change the way these stock controls look without having to retemplate them. Styles can get you pretty far and allow you to set properties like Background, BorderBrush, BorderThickness, Margin, Padding, Foreground, etc. Beyond that, you can use Triggers in Styles to set these properties differently for different control states. However, some developers have gone the route of overriding SystemColors to achieve the desired look for these elements.
To override the system-supplied ControlDark color, for example, create a SolidColorBrush whose key is SystemColors.ControlDarkKey and place it in the target control’s ResourceDictionary (or a ResourceDictionary walked by that control during resource resolution).
Here we should state that a control requiring you to go down this road is poorly designed (including parts of the WPF stock controls). Styles should be sufficient for basic reskinning and colorization. We don’t advise using this practice, and we are studying this problem so that we may provide a better mechanism.
Further reading on this from Szymon Kobalczyk's blog:
https://geekswithblogs.net/kobush/archive/2007/03/25/109753.aspx
The sample code for this tool is attached. Happy skinning!
Comments
Anonymous
November 30, 2010
I think this might be a good idea having other properties for Mouse-Hover, Defaulted Button and some other Visual States.Anonymous
December 05, 2010
@Shimmy For controls that are designed well, you can use VSM states or simple Style-level triggers to achieve specific effects for states, e.g.: <Style TargetType="TextBlock"> <Setter Property="Foreground" Value="Green"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Purple"/> </Trigger> </Style.Triggers> </Style> So, I think that if a control is designed well, there should not be a need for separate APIs exposing Brushes and other properties for these different states. A proper control template is based off of the well-known properties like BorderBrush, BorderThickness, Background, Foreground, etc. Different visual states can be achieved by manipulating these properties via triggers. Unfortunately, some of the stock templates don't respect Style-level setters like you'd expect, so it may be easier to set a new template to achieve certain visual states. However, I agree with you that additional properties make sense in some contexts. We've embraced this idea of "convenience APIs for visual states" in Ribbon. In the Ribbon scenario we have lots of sub-controls like RibbonButton, RibbonMenuButton, RibbonComboBox, etc. that should have a consistent look. You're not going to want to create a Style for each of these controls individually just to set some custom IsMouseOver look - that would be a lot of work. Therefore, we expose Ribbon.MouseOverBackground & Ribbon.MouseOverBorderBrush as convenience APIs. Set these at the Ribbon level, and all subcontrols will honor them. Pretty cool!Anonymous
December 07, 2010
Congratulations for this excellent and very helpfull article ! Given missing WPF controls like numeric up|down or domain up|down or bread crumbs, I find myself wanting a Arrow (left, right, up, down, etc.) that would match the 'current' theme. Such arrow would then comply with that one found on the scrollbars on more complex theme compliant controls like DataGrid (e.g.) Do you have any practical suggestion for "extracting" such theme compliant "arrow" primitive control. When available, it would then be used to "correctly" style UserControls I have developed. The "left, right, up, down" can probably be achieved with "LayoutTransform", though I seem to recall that rotating a top Arrow to right, down, left positions (and intermediate 45° pos) does not give the same effect as "original" corresponding drawings (I might be wrong). Thanks Paulus.Anonymous
December 14, 2010
Paulus, thank you, I'm glad you found this article helpful. Like you mentioned, the arrow buttons that are the bookends of a ScrollBar are a good example you could look at when creating your arrow control and template. You might find this resource helpful: msdn.microsoft.com/.../ms742173.aspx (ScrollBar Styles and Templates) A LayoutTransform (on the arrow glyph) might be one option. Alternatively, you could create separate glyph data for the different directions and set them using triggers (assuming arrow direction is exposed as some DependencyProperty). That's probably easiest IMO, since you'll probably set the glyph data on an arrow button like this: Content="M 4 0 L 4 8 L 0 4 Z" Hope that helps.