Overriding default SystemColors in WPF

After working with WPF for a while I must say that it is wonderful platform for building complex user interfaces but sometimes it falls short in very simple scenarios. Or in other words, it's easy to do complex things with it's powerful tools but often it lacks simple tools to do simple things. At least from a perspective of Windows Forms developer who expects some familiar tools and quickly finds out that they are gone.

There are several examples of this, but one that I run across recently and find it very often in other forums is how to change default colors in more complex controls like ListBox or ComboBox. For example yesterday there was a question on the MSDN forum on how to change the highlight color in a popup of combobox.

All controls in WPF have only three properties to adjust their colors: Foreground, Background and BorderBrush (keep in mind that all of these properties accept brushes instead of solid colors). But you won't find such properties as HighlightedItemBrush on ComboBox or SelectedItemBrush on ListBox.

I read somewhere, that primary reason for this is that Controls encapsulate logical elements and shouldn't have properties that depend on their visual representation. Instead the appearance of each control is defined through it's ControlTemplate and with some alternative template these properties might make no sense at all.

So it might seem that the only option to override these colors would be to recreate the ControlTemplate for particular control and adjust the colors. Thankfully you don't have to do it manually. With Microsoft Expression Blend you can very easily create copy of the default ControlTemplate by selecting the control and then from menu invoking Object > Edit Control Parts (Template) > Edit a Copy...

But this will only recreate the template for your current Windows Theme so if you have to preserve all other visual aspects of the control you need to put even more work to subclass your control and recreate all themes for the new control. This is quite a big effort to do such a small thing.

There is however much simpler solution if overriding the default colors is the only thing you want to change. Because these colors are defined as resources you can try to override these resource for your control.

For example, to change the color of selected item in a ListBox (or highlighted item in ComboBox ) override following resource:

<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Orange" />

And because I also wanted to have the same color when ListBox doesn't have focus I needed to override this resource as well:

<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Orange" />

As with all resources you can do it either only for this particular control (using Style.Resources), whole window or even for the whole application depending on which ResourceDictionary you would use. And because these resources are referenced as DynamicResource you can even adjust them at runtime.  

So now the only problem is to find out what resources you need to override to get the desired control. Once again the Microsoft Expression Designer comes in handy and you can find this out by recreating the default templates but this time only to read what colors it uses and what what purpose.

I've started putting together a reference of which system colors are used in default templates for simple controls and will publish it shortly.

This article is part of the GWB Archives. Original Author: Szymon Kobalczyk

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.