Wednesday, April 7, 2010

A Chrome and Glass Theme - Part 3

In the first two parts I covered how to use Blend to create reusable resources for brushes and styles, and we styled a Border control and a Button control.

In this post we are going to style two more relatively simple controls: a TextBox, and a CheckBox. So start by re-opening your solution from last time (you can grab it here if you haven't been following along). This is what the final styles will look like:

You can grab the solution containing these styles here.

First: Improve the Button
But first, I want to quickly revisit the Button style we created last time - after playing around with it some more, I don't like the way it looks when it's disabled. We didn't change the default disabled state appearance, which grays-out the control by changing the opacity of the "DisabledVisualElement" rectangle. The problem is that when the button is disabled, it actually stands out more than any enabled buttons around it - which it shouldn't.

To fix it, we are going to give it a glassy look when it's disabled.

Select the button we created last time and use the bread crumb trail to edit the control template. Open up the Object tree and select the grid control under the "Background" Border control. Click the Advanced Properties Options button on the right of the Background brush and select "Reset" to get rid of the link to the template background color.

Select the "DisabledVisualElement" and change it's Fill to a linear gradient with the following markers:
  1. #FFFFFFFF Position: 12.7%
  2. #FFCDCDCD Position 32.8%
  3. #FF898989 Position 35.2%
  4. #FFC2C2C2 Position 39.6%
  5. #FFB3B3B3 Position 49.3%
  6. #FFFFFFFF Position 52.4%
  7. #FF252525 Position 55.6%
  8. #FF808080 Position 100%
And click the little down arrow below the brush editor to show the advanced properties of the gradient brush, and change the Opacity of the whole brush (not the rectangle) to 31%. Now convert that to a new resource called "ChromeGlassFill" in our ChromeGlass resource dictionary.

Finally, select the "Disabled" state, set the Opacity of the BackgroundGradient rectangle to 0%, the Opacity of the DisabledVisualElement rectangle to 100%, and the Opacity of the ContentPresenter to 50%. And set the margins of the DisabledVisualElement to 2. Use the Bread Crumb Trail to exit the style template back into the MainPage. The image to the left shows the button now in it's different enabled states.

The TextBox Control
Before we create a TextBox control we have to group our existing button into a Grid since a Border can only contain one control. Right click the button and press Ctrl + G to group it into a Grid control. Blend will have set the margins on the grid to fit exactly around the button, and changed the button horizontal and vertical alignments to Stretch so reset the margins of the new Grid back to 0, make sure the horizontal and vertical alignments are both Stretch, and the Width and Height are both Auto. Of course now our button takes up the entire grid, so change it's width back to 140, and it's height back to 30. And drag it back into place.

Now add a TextBox control to the Grid, make it about the same size as the button. From the Object menu, select "Edit Style" | "Edit Copy..." and save it as "TextBloxGlassyStyle" in our ChromeGlass resource dictionary. Set it's Background brush to our new "ChromeGlassFill" brush, and it's border to the "ChromeBorder" fill. Set the Foreground brush to a white solid color, the CaretBrush to a white solid color, and the SelectionForeground to black.

Now use the Breadcrumb Trail to edit the current template and open up the object tree. Select the self-named "Border" control and reset it's Background brush to be empty - we are going to animate the opacity of the background, but if we do it on the Border then it will also affect it's child controls.

Create two new rectangles inside the Grid called "UnfocusedBackground" and "EditingBackground" positioned as the first children of the grid as shown in the image to the left. Make sure the margins of the rectangles are reset to 0, the horizontal and vertical alignments are set to Stretch, and the Width and Height set to Auto.

Select the UnfocusedBackground rectangle and use the Advanced Property Options button on it's Fill to use Template Binding to the Template's Background property. Set it's stroke to No Brush.

Select the EditingBackground rectangle, set it's Fill to #4CFFFFFF, and it's Opacity to 0%.

Make the following changes to the Focused State:
  • Set the UnfocusedBackground Opacity to 0%
  • Set the EditingBackground Opacity to 100%
  • Set the FocusVisualElement Opacity to 50%
  • Set the FocusVisualElement Margins all to 0
And these changes to the Disabled State:
  • Set the Border Opacity to 75%
  • Set the ContentElement Opacity to 50%
  • Set the DisabledVisualElement Opacity to 0%

That's our TextBox done. Exit the Style Template and run the solution to try it out.

The CheckBox Control
Create a CheckBox control and use the same technique as for the TextBox control to create a style called "CheckBoxGlassyStyle" in our resource dictionary.

While editing the style, set the BorderBrush to our ChromeBorder LinearBrush resource and set the Foreground to White. Now use the Breadcrumb Trail to edit the control template and make the following changes to the controls inside the template (you can ignore the warnings about animations being removed):
  • Set the Background control's Fill to our GlassFill resource
  • Set the BoxMiddleBackground control's Fill to our ChromeFill resource (you will have to Reset it first)
  • Set the BoxMiddle control's Fill to our ChromeGlassFill resource and it's Stroke to our GlassBorder resource
  • Set the CheckIcon control's Fill to white
  • Set the IndeterminateIcon control's Fill to our ChromeFill resource
You can see the benefit of saving our linear gradient brushes as resources - that saves us a lot of time!

Now we just need to update the states:

MouseOver State
  • Set the BackgroundOverlay Opacity to 30%
  • Set the BoxMiddleBackground Opacity to 30%
Pressed State
  • Set the BackgroundOverlay Opacity to 0%
  • Set the BoxMiddleBackground Opacity to 100%
Focused State
  • Set the ContentFocusVisualElement Opacity to 50%
And that's it! Exit the template back into the Main Page and run your solution.

In the sample at the top of the post I've bound the IsEnabled property of the TextBox and Button to the CheckBox so you can see what they look like disabled.

You can grab the solution containing the above styles here.


  1. Looks Good Phil.
    You have inspire another idea, so here it is. I wonder what it would look like if you flip the text box gradient to produce an inset space (as apposed to a protrusion)?

    Have fun in New Zealand
    Mike Greenway

  2. Hi Mike, thanks for the feedback.

    Grab the solution from the link in the post and try out your idea. Let me know if it works well!

  3. After seeing it, I like your version better.
    Thank for sharing your work.
    and templating controls is a lot of work!
    Have you played with a slider yet?

  4. I will get to the slider eventually - there are quite a few controls to get through!