Control Styling Tips: Button
Hello!
In this article, I’d like to provide you with some information and tips that you’ll find useful when styling a Silverlight 3 Button.
Visual states. CommonStates (Normal, MouseOver, Pressed and Disabled) and FocusStates (Unfocused and Focused).
Template parts. None.
Template binding. Try template binding Background, BorderBrush, Foreground, BorderThickness or Padding.
Make Into Control, where content is text. A visual designer has comped out some Button states:
The comp artwork is then imported into Blend 3. Here’s the XAML for the Normal state. Note, this XAML is not yet a styled Button, it is still just artwork consisting of Panels and Shapes and text.
<Grid MinWidth="79" MinHeight="20" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Fill="#FF3D3D3D" Stroke="#FF3D3D3D" RadiusX="3" RadiusY="3"/>
<TextBlock Foreground="LightGray" Text="OK" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
Practice making the artwork into a Button with the following steps.
- Paste the XAML into a new Silverlight 3 Application project.
- Select [Grid] and click Tools > Make Into Control > Button > OK. Blend has done a lot of work in this one step. First, Blend removed the Grid (and everything inside it) and put a new Button in its place. Next, it turned the Grid into the template of a new Button style and applied that new style to the new Button. The TextBlock in the Grid had a LightGray forground, so the new Button style has a LightGray foreground too. The TextBlock’s text was ‘OK’ so that becomes the content of the new Button. And, in the template, the TextBlock has been replaced with a ContentPresenter that has the same layout properties as the TextBlock had.
- Now to make the template’s states look like those in the visual designer’s comp. Ensure the States panel is open and select the MouseOver state. Set [Rectangle] ’s Fill and Stroke properties to Gray. Note that the Rectangle now has a name: rectangle.
- Instead of making the same changes to Pressed, let’s save time and copy the MouseOver state to Pressed. With MouseOver still selected, click Tools > Copy State To > Pressed.
- Select the Pressed state. To offset the text to look like it does in the comp, select [ContentPresenter] and set RenderTransform.Translate.X and .Y to 1.
- Select the Disabled state. Select rectangle and set its Fill to Transparent and its Stroke to LightGray.
- To give some life to the MouseOver state, click the ‘Add transition’ button on the Normal state and click Normal -> MouseOver. Set the transition’s duration to 0.2 seconds. When we move the mouse onto the Button, the transition from Normal to MouseOver will take 0.2s. All other transitions, including the transition back to Normal when the mouse is moved away, and the transition from Pressed to MouseOver when the mouse button is released after a click, will happen instantly. Instant transitions are the default, and that’s what we want in all these other cases.
- The visual designer drew a blue rounded rectangle in the Focused state. But the rectangle is not present in the XAML of the Normal state so we’ll need to draw it into the template now. Creating a new object with a state selected is called ‘drawing into state’ and it means that the new object is only visible in the state you drew it into. This is a useful feature that we can make use of now. Select Focused and double-click the Rectangle tool to create one default-sized.
- We now want to change the size and color of the new rectangle (rectangle1) but we want those changes to be made to Base and not to the Focused state. We can’t select Base because the Rectangle is transparent in Base so we won’t see the changes we’re making. So, instead, click the ‘Turn off record mode’ button on the Focused state (or click Ctrl+R). Now change rectangle1’s Margin to Left:1, Right:1, Top:1, Bottom:1, set its Fill to No brush, its Stroke color to #FF00C0FF and its RadiusX and RadiusY to 2.
- As an optional step, if you want the focus rectangle to do something more interesting (dramatic, even) while the Button has focus, then you can create a steady-state animation. Select the Focused state and click the Show Timeline button above the object tree. Drag the Opacity keyframe out to the 2 second mark. Move the playhead to 2.2 seconds, select rectangle1 and set Opacity to 0. Move the playhead back to time 0 and set rectangle1’s RenderTransform.Scale.Scale X and .Scale Y to 5. Select the RenderTransform keyframe at time 2 and set its EasingFunction to Quartic Out. Click the state’s name immediately below the Objects and Timeline tab and set RepeatBehavior to Forever.
- Return scope to [UserControl] . Copy-Paste the Button a couple of times and set one copy’s IsEnabled to false. Build and run your application and test your states.
Make Into Control, where content is a graphic. A visual designer has comped out some Button states:
The comp artwork is then imported into Blend 3. Here’s the XAML for the Normal state.
<Grid Width="17" Height="17">
<Rectangle Fill="#FF3D3D3D" Stroke="#FF3D3D3D"/>
<Path x:Name="content" Fill="LightGray" Stretch="Fill" Width="7" Height="7" Data="M196.89876,311.82065 L204.06047,311.82065 L200.42426,304.87872 z" Margin="0,5,0,0" VerticalAlignment="Top"/>
</Grid>
Practice making the artwork into a Button with the following steps.
- Paste the XAML into a new Silverlight 3 Application project.
- Select [Grid] and click Tools > Make Into Control > Button > OK. In this step, Blend removed the Grid (and everything inside it) and put a new Button in its place. Next, it turned the Grid into the template of a new Button style and applied that new style to the new Button.
- Select content and Cut. Return scope to [UserControl] and Paste.
- Making the template’s states look like those in the visual designer’s comp is the same as in the previous example with the one exception that the focus rectangle is not rounded.
You should now have a working Button!
- Steve
Comments
Anonymous
September 16, 2009
Good stuff Thanks. But why would the recommendation be to replace the content presenter in the button template with static content? Wouldn't it make more sense to stick to the content model and place a content presenter in the template, or at the very least (in the first example) Template bind the text property to the content property?Anonymous
October 04, 2009
The comment has been removedAnonymous
October 08, 2009
Nice. I'd really love to see how you rotate text so it fits into a button that's very narrow and tall. (The problem is in the sequence of the transform, occurring after the text is in the button, so it doesn't stay in the button, or it gets truncated before it can be rotated.)