Changing the Look of a Control with a Custom

ControlTemplate

You've now seen how you can set multiple properties of a particular type of control using the Style object. These properties all affect the look of the control in some way, often by changing the FontStyle, the Foreground, or perhaps the default Height or Width. When your customization needs outgrow simple property settings, you need to customize the ControlTemplate.

Overriding the ControlTemplate is achieved in the Style by setting the Template property. Remember, a Style is just a collection of Setters, and the Template property is the most powerful property you can set.

What Is a ControlTemplate?

At the beginning of this chapter, I said that a ControlTemplate is the VisualTree of elements that make up the look of a control. These elements can range from a series of nested Borders (like the default Button) to a combination of paths with complex gradient fills. A ControlTemplate is generally applied by a Style. In Silverlight, just like WPF, controls are said to be lookless. The definition of a control's properties is independent from the actual look of the control. The look of the control is defined in XAML and is applied at compile time.

Why Define a Custom Template?

Acknowledging that Silverlight controls are lookless is one thing, but understanding why they are look-less is another. Because a control is lookless, you can completely replace its visual appearance. Let's consider the Button for a moment. The Button control is probably the most commonly retemplated control in both Silverlight and WPF. Consider the immersive Web experiences or applications you've encountered over the years. A core action of your experience is clicking. You click, click, click — text, images, custom artwork — anything is fair game. Generally, the item you are clicking responds to the MouseOver and MousePressed events, providing you with visual feedback to your interaction.

If I ask you to picture different button styles that you've encountered, your mind probably fills will different shapes, colors, and textures — imprints left by the many visually diverse experiences you've had in your travels. If your mind didn't fill with images, at least consider the differing appearance between a Windows Vista button and an OS X button. The two buttons react to the same interaction (MouseOver, MousePressed, Disabled) and generally fire the same events for developers (e.g., Click), but their appearance is markedly different.

Your application will likely need the functionality provided by Buttons, ListBoxes, RadioButtons, and CheckBoxes, but your brand may require a look other than the default look provided by Silverlight. By retemplating the controls, you get the same functionality provided out-of-the-box with the added benefit of having your custom look applied.

Defining and Applying a Custom Template

Before we retemplate the Button, let's add a default-styled Button to the page for comparison. Figure 8-3 shows the default Silverlight Button on the stage in Blend. All of the visual elements that make up the look of the button reside in the Button's default template. Later, we'll look at the XAML that makes up the default button; for now, I want to call out a few key elements. Notice the single-pixel gray border with rounded corners — that's defined by a Border element. In the foreground of that Border element is another border with a gradient fill. In the foreground of that element is a rounded piece of artwork that simulates a highlight. Finally, there is an element that displays the Content we have specified on the button. It is center-aligned both vertically and horizontally.

Figure 8-3

A custom template is defined using the same layout panels and controls you've been introduced to throughout this book. Everything in your Silverlight arsenal is fair game for a control's template. The following code shows a simple Style that sets the Template property of a Button control, replacing the default template with a Grid containing a nested red Rectangle:

<Style x:Key="customStyle" TargetType="Button"> <Setter Property="Template" >

<Setter.Value>

<ControlTemplate TargetType="Button"> <Grid>

<Rectangle Fill="#FF0000" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

Here, for the first time in this chapter, you're seeing the more verbose way of setting the Value property of a Setter. Because the value we are supplying is much more complex than a single string value, we have to set the Value property by using <Setter.Value />. The value of the Template property is always a ControlTemplate object whose TargetType property matches the value of the Style object it is defined within. The ControlTemplate object accepts a single child element whose value is always some type of Panel; in this case, it's a Grid.

Unlike WPF, the value of the TargetType property is just a string and does not require the {x:Type ControlName} syntax.

Applying this Style to a Button is achieved by setting the Style property, just like we did for the TextBlock example before:

<Button Style="{StaticResource customStyle}" Content="Click Me!" HorizontalAlignment="Center" VerticalAlignment="Center"/>

Applying this Style to a Button results in a button that looks like a flat, red rectangle like the button depicted in Figure 8-4. We've completely replaced the default template of the button with a single rectangle.

Figure 8-4

Not too exciting, eh? And where is the text "Click Me!" as specified on the Content property? Since we have completely replaced the template of the Button with a Grid and nested Rectangle, we have eliminated the Button's ability to display its own content! See, the Template property really is the most powerful property of all. As we define the template of a control, we have to think about how we want the control's property values to affect the way the control actually looks. Let's deal with the content issue first.

The ContentPresenter

The ContentPresenter control, just as its name indicates, is used to display content. All controls derived from ContentControl have a Content property. Button happens to be derived from ContentControl, which is why you set its Content property instead of its Text property. The Content property is of type UlElement, which means pretty much any visual element can be thrown at it, even another Button.

In order to display the text "Click Me!" as set on our Button's Content property, we need to add a ContentPresenter to our custom template defined in customStyle. The following XAML shows this ContentPresenter in place:

<Style x:Key="customStyle" TargetType="Button"> <Setter Property="Template" > <Setter.Value>

<ControlTemplate TargetType="Button"> <Grid>

<Rectangle Fill="#FF0000" />

<ContentPresenter Margin="5,5,5,5" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

That's all there is to it. It's actually deceptively simple. The ContentPresenter, when dropped into a ContentControl, automatically detects the type of content that has been set and displays it accordingly. When the content is text, as in this example, a TextBlock is automatically created whose Text property is set to the value specified.

Try setting the Content of the button to different types of objects (Circles, Rectangles, ComboBoxes, etc.) and notice how each of these objects is displayed inside the custom template. Figure 8-5 shows some of the variations that are possible. And remember, you can affect the layout of the ContentPresenter by using the HorizontalAlignment, VerticalAlignment, and Margin properties (or any other layout properties) as with any other control.

Button

0 0

Post a comment

  • Receive news updates via email from this site