WPF: Dynamic Button Background


I have recently been asked the following question, paraphrasing a little:
How do I change the background brush of a Button based on the background of the container panel by using a key-less Style?
The short answer is that I would use a value converter to look at the background colour for the desired container, and then return a Brush based on that, here's the code for the converter:

This code expects the incoming value parameter to be of type Panel, if it is not, then the converter simply returns the system brush for a control background.

If the object is a Panel and the background brush is a SolidColorBrush then check for the target colour; Khaki in this case. If so, then change the background colour to Orange. If the container is correct, but the colour is not, then set the background colour to Khaki instead.

Note that I've baked the colours into this code to keep the sample simple, however, in a real world application all the brushes would be resources and the converter would use those instead.

The next step is to wire this converter in to the XAML:

First I've added the value converter to the mark-up by using an l: prefix, and then added the value converter to the resources. Next, I've create a default style for all Buttons, by not using a key for Style resource, and then created a Setter for the Background property. Next, I've use a RelativeSource markup extension, looking for parent panel type I care about, a Grid in this case in a Binding, finally applying the converter to the binding.

Next, I've added three buttons to the view, to prove the style works:
  1. A Button in a StackPanel acting as the layout root,
  2. A Button wrapped in a Grid, but with the default background colour,
  3. Finally, a Button wrapped in a Grid and with the target background colour
The output looks as follows:

And there you have it; dynamic Button backgrounds based on the parent Panel. You can download the code from here:
I would like to point out that if the target object was to be a data object, e.g. a ViewModel or any model object, as opposed to a Button, I would use a different technique; in that case I would use a DataTemplateSelector or a DataTrigger. If anyone is interested in seeing that code then please leave me a comment and I'll put something together.

That's it for now, and as usual, if you have any comments, questions, flames, or enhancements I would love to hear from you. In the meantime, think deeply and enjoy.


No comments: