Chapter 12. Styling in Silverlight

Of course you will want to create a rich appearance for your Silverlight application. You'll make choices about your design. What font size and family will you use? How much space will you place between your objects? What size of text boxes and buttons will you use?

As you'll learn in this chapter, you can control the styles of your Silverlight application's UI elements in several ways. The first approach you will explore is the straightforward use of inline properties. Then you will look at how to define and apply Silverlight styles.

Inline Properties

You can simply define style properties directly in the object definitions. As an example, the following code snippet sets the FontFamily, FontSize, FontWeight, and Margin properties within the TextBlock itself.

<TextBlock
    Grid.Row="0"
    Grid.Column="0"
    Text="First Name"
    FontFamily="Verdana"
    FontSize="16"
    FontWeight="Bold"
    Margin="5" />

You can set inline properties using either Visual Studio or Expression Blend. Let's try out both.

Try It Out: Setting Inline Properties with Visual Studio

The following exercise demonstrates how to use Visual Studio 2010 to define the appearance of your Silverlight applications with inline properties. In this exercise, you will create the UI for a simple data-input application. You will not add any logic to the application, since the focus is on the appearance of the controls.

  1. Open Visual Studio 2010 and create a new Silverlight application named Ch12_VSInlineStyling. Allow Visual Studio to create a Web Application project to host the application.

  2. When the project is created, you should be looking at the MainPage.xaml file. If you do not see the XAML source, switch to that view. Start by adjusting the size of the UserControl to get some additional space in which to work. Set Height to 400 and Width to 600, as follows:

    <UserControl x:Class="Ch12_VSInlineStyling.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="600" Height="400">
        <Grid x:Name="LayoutRoot" Background="White">
    
        </Grid>
    </UserControl>
  3. Add four rows and two columns to the root Grid. Set the width of the left column to 150, leaving the rest of the row and column definitions unspecified, as follows:

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
    </Grid>

    Next, add TextBlock controls in the three top-left columns and TextBox controls in the top-right columns, with the text First Name, Last Name, and Age. Then add three Button controls within a horizontal StackPanel in the bottom-right column. Give these buttons the labels Save, Next, and Delete. (Again, you won't be adding any logic to these controls; you will simply be modifying their appearance.) The code for this layout follows:

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="First Name" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name" />
        <TextBlock Grid.Row="2" Grid.Column="0" Text="Age" />
    
        <TextBox Grid.Row="0" Grid.Column="1" />
        <TextBox Grid.Row="1" Grid.Column="1" />
        <TextBox Grid.Row="2" Grid.Column="1"  />
    
        <StackPanel Grid.Row="3" Grid.Column="2" Orientation="Horizontal">
            <Button Content="Save" />
            <Button Content="Next" />
            <Button Content="Delete" />
        </StackPanel>
    </Grid>
  4. Press F5 to start the application. You will see that the UI you have created is far from attractive, as shown in Figure 12-1. So let's make this ugly UI look a bit nicer by adding some styling.

    Default input form without styling

    Figure 12.1. Default input form without styling

  5. Start with the three TextBlock controls. Within Visual Studio, set the FontFamily, FontSize, FontWeight, and Margin properties directly within each TextBlock definition, as shown in the following code snippet. As you type the property names, you will notice that IntelliSense makes this task a bit less tedious. Once you have set the four properties on the First Name TextBlock, copy and paste the properties to the other two TextBlock controls.

    <TextBlock Grid.Row="0" Grid.Column="0" Text="First Name"
        FontFamily="Verdana"
        FontSize="16"
        FontWeight="Bold"
        Margin="5" />
    <TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name"
        FontFamily="Verdana"
        FontSize="16"
        FontWeight="Bold"
        Margin="5" />
    <TextBlock Grid.Row="2" Grid.Column="0" Text="Age"
        FontFamily="Verdana"
        FontSize="16"
        FontWeight="Bold"
        Margin="5" />
  6. Run the application again. You can see the changes that have been made to the TextBlock labels, as shown in Figure 12-2.

    Input form with styled TextBlock labels

    Figure 12.2. Input form with styled TextBlock labels

  7. Now let's focus on the TextBox controls. Add the following style attributes to these controls.

    <TextBox Grid.Row="0" Grid.Column="1"
        VerticalAlignment="Top"
        Height="24"
        Margin="5"
        FontSize="14"
        FontFamily="Verdana"
        Foreground="Blue"
        Background="Wheat" />
    
    <TextBox Grid.Row="1" Grid.Column="1"
        VerticalAlignment="Top"
        Height="24"
        Margin="5"
        FontSize="14"
        FontFamily="Verdana"
        Foreground="Blue"
        Background="Wheat" />
    
    <TextBox Grid.Row="2" Grid.Column="1"
        VerticalAlignment="Top"
        Height="24"
        Margin="5"
        FontSize="14"
        FontFamily="Verdana"
        Foreground="Blue"
        Background="Wheat" />
  8. Run the application to see the effect. It should look like Figure 12-3.

    Input form with styled TextBox controls

    Figure 12.3. Input form with styled TextBox controls

    Notice that the spacing between the rows is too large. Ideally, the spaces should only be large enough to allow the margins of the controls to provide the separation. To adjust this spacing, on each RowDefinition, change the Height property to Auto, as follows:

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
  9. Once more, run the application to see how it looks at this point. Figure 12-4 shows the results of the automatic height settings.

    Input form with styled RowDefinitions

    Figure 12.4. Input form with styled RowDefinitions

  10. The next elements to tackle are the Button controls. Add the following style attributes to these three controls:

    <Button Content="Save"
        FontFamily="Verdana"
        FontSize="11"
        Width="75"
        Margin="5" />
    
    <Button Content="Next"
        FontFamily="Verdana"
        FontSize="11"
        Width="75"
        Margin="5" />
    
    <Button Content="Delete"
        FontFamily="Verdana"
        FontSize="11"
        Width="75"
        Margin="5" />
  11. Run the application to see the effect. It should look like Figure 12-5.

    Input form with styled buttons

    Figure 12.5. Input form with styled buttons

  12. Finally, it would be nice to add a margin around the entire application. To do this, simply add a Margin property definition to the root Grid, as follows:

    <Grid x:Name="LayoutRoot" Background="White" Margin="25">
  13. Press F5. The final product is a UI that looks pretty nice, as shown in Figure 12-6.

As you saw in this exercise, the process of setting inline properties in Visual Studio is simple and straightforward. However, the sample application contained only nine controls. You will look at some better options later in this chapter, in the "Silverlight Styles" section. Next, let's see how to set inline properties within Expression Blend.

Final input form styled with inline properties

Figure 12.6. Final input form styled with inline properties

Try It Out: Setting Inline Properties with Expression Blend

The previous example used Visual Studio to set the inline properties of an application's controls. For those of you who are not a big fan of a lot of typing, you may find that Expression Blend is a better place to set these properties. In this next exercise, you will perform the same styling as in previous exercise, but using Expression Blend to set the properties, rather than Visual Studio 2010. Let's give it a try!

  1. Open Expression Blend and create a new Silverlight 4 application named Ch12_BlendStyling.

  2. The UserControl is 640 by 480 by default when created in Expression Blend, so you can leave that size. The first thing to do is add the column and row definitions. You can copy and paste the grid definitions from the previous exercise, or you can add the columns and rows using Expression Blend's grid editor, as described in Chapter 9. The end result should look like Figure 12-7.

  3. Next, add the controls to the form. In the Toolbox, double-click the TextBlock control three times to add three TextBlock controls to the grid. Then double-click the TextBox control three times, which will add three TextBox controls below the TextBlock controls.

  4. Double-click the StackPanel layout control. Once the StackPanel is added, double- click it in the Objects and Timeline panel so that it is outlined, as shown in Figure 12-8.

    Completed grid layout

    Figure 12.7. Completed grid layout

    Selecting the StackPanel in the Objects and Timeline panel

    Figure 12.8. Selecting the StackPanel in the Objects and Timeline panel

    With the StackPanel selected, double-click the Button control three times. The three Button controls will appear within the StackPanel, as shown in Figure 12-9.

    The Button controls added to the StackPanel

    Figure 12.9. The Button controls added to the StackPanel

    By default, Expression Blend adds a number of properties that you don't want. In the next steps, you'll remove the properties shown in bold in the following XAML:

    <Grid x:Name="LayoutRoot" Background="White" >
       <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
       </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150"/>
          <ColumnDefinition/>
       </Grid.ColumnDefinitions>
       <TextBlock HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap"/>
       <TextBlock HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap"/>
       <TextBlock HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap"/>
       <TextBox HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBox" TextWrapping="Wrap"/>
       <TextBox HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBox" TextWrapping="Wrap"/>
       <TextBox HorizontalAlignment="Left"
          VerticalAlignment="Top" Text="TextBox" TextWrapping="Wrap"/>
       <StackPanel Margin="0,0,50,20">
          <Button Content="Button"/>
          <Button Content="Button"/>
          <Button Content="Button"/>
       </StackPanel>
    </Grid>
  5. In the Objects and Timeline panel, highlight all of the TextBlock and TextBox controls, as shown in Figure 12-10. You can highlight multiple items in the Objects and Timeline panel by holding down the Shift or Ctrl key as you click.

    Selecting multiple objects in the Objects and Timeline panel

    Figure 12.10. Selecting multiple objects in the Objects and Timeline panel

    With these six controls selected, look in the Properties panel. Notice that any property that is set in the XAML has a white dot to its right. (Properties you cannot edit have a gray dot.) You can easily remove these properties from the XAML and "reset" the code by clicking the white dot and selecting Reset. Start out by resetting the HorizontalAlignment property located in the Layout section of the Properties panel, as shown in Figure 12-11. Then reset the VerticalAlignment property. This will remove the HorizontalAlignment and VerticalAlignment property definitions in the XAML.

    Resetting the HorizontalAlignment property

    Figure 12.11. Resetting the HorizontalAlignment property

  6. The TextWrapping property is located in the Text Section of the Properties panel, but you must extend the section to see it. I figured that this would be a good opportunity to show you another feature of the Properties panel. At the top of the Properties panel, type TextWrapping into the Search box. That will filter the Properties panel to show only the TextWrapping property. Click and reset that property as well.

  7. Next, highlight the StackPanel and reset its Margin property in the same way. When you have finished all of these steps, the XAML should contain the following source code:

    <Grid x:Name="LayoutRoot" Background="White" >
       <Grid.RowDefinitions>
         <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
       </Grid.RowDefinitions>
       <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150"/>
          <ColumnDefinition/>
       </Grid.ColumnDefinitions>
       <TextBlock Text="TextBlock"/>
       <TextBlock Text="TextBlock"/>
       <TextBlock Text="TextBlock"/>
       <TextBox Text="TextBox"/>
       <TextBox Text="TextBox"/>
       <TextBox Text="TextBox"/>
       <StackPanel>
          <Button Content="Button"/>
          <Button Content="Button"/>
          <Button Content="Button"/>
       </StackPanel>
    </Grid>
  8. Now you need to place these controls in the proper cells in your grid. Click to highlight the control in the Objects and Timeline panel. In the Layout section of the Properties panel, you will see Row and Column properties. Set their values so that you have the following result:

    <Grid x:Name="LayoutRoot" Background="White" >
       <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
       </Grid.RowDefinitions>
       <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150"/>
          <ColumnDefinition/>
       </Grid.ColumnDefinitions>
       <TextBlock Text="TextBlock"/>
       <TextBlock Text="TextBlock" Grid.Row="1"/>
       <TextBlock Text="TextBlock" Grid.Row="2"/>
       <TextBox Text="TextBox" Grid.Column="1"/>
       <TextBox Text="TextBox" Grid.Column="1" Grid.Row="1"/>
       <TextBox Text="TextBox" Grid.Row="2" Grid.Column="1"/>
    <StackPanel Grid.Column="1" Grid.Row="3">
          <Button Content="Button"/>
          <Button Content="Button"/>
          <Button Content="Button"/>
       </StackPanel>
    </Grid>
  9. Go through each of the TextBlock controls to set the Text properties to First Name, Last Name, and Age. Next, set the Text property of the TextBox controls to blank (or just reset the property). Then set the Orientation property for the StackPanel to Horizontal. Finally, set the Content property for the Button controls to Save, Next, and Delete. The final result should be the following:

    <Grid x:Name="LayoutRoot" Background="White" >
       <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
          <RowDefinition/>
       </Grid.RowDefinitions>
       <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150"/>
          <ColumnDefinition/>
       </Grid.ColumnDefinitions>
       <TextBlock Text="First Name"/>
       <TextBlock Text="Last Name" Grid.Row="1"/>
       <TextBlock Text="Age" Grid.Row="2"/>
       <TextBox Grid.Column="1"/>
       <TextBox Grid.Column="1" Grid.Row="1"/>
       <TextBox Grid.Row="2" Grid.Column="1"/>
       <StackPanel Grid.Column="1" Grid.Row="3" Orientation="Horizontal">
          <Button Content="Save"/>
          <Button Content="Next"/>
          <Button Content="Delete"/>
       </StackPanel>
    </Grid>
  10. Run the solution, and you will see the initial layout, which should look the same as what you started with in the previous exercise (Figure 12-1). The next thing to do is set the style properties for your controls.

    Highlight all three TextBlock controls. In the Properties panel, set the following properties:

    • FontFamily: Verdana

    • FontSize: 16

    • FontWeight: Bold

    • Margin: 5,5,5,5

  11. Select the three TextBox controls and set the following properties:

    • FontFamily: Verdana

    • FontSize: 14

    • FontWeight: Bold

    • Foreground: #FF0008FF

    • Background: #FFF9F57D

    • VerticalAlignment: Top

    • Margin: 5,5,5,5

  12. Highlight the three Button controls and set the following properties:

    • FontFamily: Verdana

    • FontSize: 11

    • Width: 75

    • Margin: 5,5,5,5

  13. Switch to split-view mode. Within the XAML, place your cursor within one of the RowDefinition items. Then, in the Properties panel, set the Height property to Auto. Repeat this for all of the RowDefinition items in the Grid. When you are finished setting the Height properties on the RowDefinition items, the XAML for the application should be as follows:

    <Grid x:Name="LayoutRoot" Background="White" >
       <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="Auto"/>
       </Grid.RowDefinitions>
       <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150"/>
          <ColumnDefinition/>
       </Grid.ColumnDefinitions>
       <TextBlock Text="First Name" FontFamily="Verdana"
           FontSize="16" FontWeight="Bold" Margin="5,5,5,5"/>
       <TextBlock Text="Last Name" Grid.Row="1" FontFamily="Verdana"
           FontSize="16" FontWeight="Bold" Margin="5,5,5,5"/>
       <TextBlock Text="Age" Grid.Row="2" FontFamily="Verdana"
           FontSize="16" FontWeight="Bold" Margin="5,5,5,5"/>
       <TextBox Text="" Grid.Row="0" Grid.Column="1"
           FontFamily="Verdana" FontSize="14" FontWeight="Bold"
           Foreground="#FF0008FF" Background="#FFF9F57D"
           VerticalAlignment="Top" Margin="5,5,5,5"/>
    <TextBox Text="" Grid.Row="1" Grid.Column="1"
           FontFamily="Verdana" FontSize="14" FontWeight="Bold"
           Foreground="#FF0008FF" Background="#FFF9F57D"
           VerticalAlignment="Top" Margin="5,5,5,5"/>
       <TextBox Text="" Grid.Row="2" Grid.Column="1"
           FontFamily="Verdana" FontSize="14" FontWeight="Bold"
           Foreground="#FF0008FF" Background="#FFF9F57D"
           VerticalAlignment="Top" Margin="5,5,5,5"/>
       <StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal">
          <Button Content="Save" Margin="5,5,5,5"
             Width="75" FontFamily="Verdana"/>
          <Button Content="Next" Margin="5,5,5,5"
              Width="75" FontFamily="Verdana"/>
          <Button Content="Delete" Margin="5,5,5,5"
              Width="75" FontFamily="Verdana"/>
          </StackPanel>
    </Grid>
  14. Your application will appear something like what is shown in Figure 12-12. When you run the application, it should look very similar to the application at the end of the previous exercise (Figure 12-6).

    Final project in Expression Blend

    Figure 12.12. Final project in Expression Blend

Getting the code perfect is not the point of this exercise. It's OK if your application doesn't look exactly like my screenshot. The main objective was to get you familiar with setting and resetting inline properties in Expression Blend.

In these two exercises, you saw how to change the appearance of your Silverlight applications using inline properties in Visual Studio 2010 and Expression Blend. Although this method is very straightforward, in a normal application with a lot of controls, setting all of the properties can become tedious. And if you need to change the appearance of some elements throughout the application, it will not be an easy task. This is where Silverlight styles come in.

Silverlight Styles

In the previous section, you saw how you can change the appearance of a Silverlight application by setting inline properties. This works perfectly fine, but it presents maintenance problems. From a maintenance perspective, it's better to separate the style properties from the control definitions. For example, consider the following TextBlock definition:

<TextBlock
    Grid.Row="0"
    Grid.Column="0"
    Text="First Name"
    FontFamily="Verdana"
    FontSize="16"
    FontWeight="Bold"
    Margin="5" />

Suppose you defined all your TextBlock controls this way, throughout your application. Then, if you wanted to update the look of your application's text boxes, you would need to modify the TextBox definitions one by one. To save time and avoid errors, it's preferable to be able to make updates to properties related to the control's appearance in one central location, rather than in each instance of the control.

This problem is certainly not new to Silverlight. Developers and designers have faced this challenge for years with HTML-based pages. HTML solves the problem with a technology known as Cascading Style Sheets (CSS). Instead of specifying the different attributes of HTML controls directly, developers can simply specify a style for the control that corresponds to a style in a style sheet. The style sheet, not the HTML, defines all of the different appearance attributes for all controls. This way, if developers want to adjust an attribute of a control in an application, they can change it in the style sheet one time, and that change will be automatically reflected in every control in the application that references that style.

Silverlight offers a similar solution. Silverlight allows you to create style resources, in much the same way you would define styles in a CSS style sheet. In Silverlight, style resources are hierarchical, and can be defined at either the page level or the application level. If defined at the page level, the styles will be available only to controls on that page. Styles defined at the application level can be utilized by controls on all pages across the entire application. The "Silverlight Style Hierarchy" section later in this chapter provides more information about the style hierarchy.

A Silverlight style is defined using the <Style> element, which requires two attributes: the Key attribute represents the name of the style, and the TargetType attribute tells Silverlight which type of control gets the style. Within the <Style> element, the style is made up of one or more <Setter> elements, which define a Property attribute and a Value attribute. As an example, the preceding TextBlock control's appearance properties could be defined in the following Silverlight style definition:

<Style x:Key="FormLabel" TargetType="TextBlock">
   <Setter Property="FontFamily" Value="Verdana"/>
   <Setter Property="FontSize" Value="16"/>
   <Setter Property="FontWeight" Value="Bold"/>
   <Setter Property="Margin" Value="5,5,5,5"/>
</Style>

In HTML, to reference a style from a control, you simply set the style attribute. In Silverlight, this syntax looks a little different. Silverlight styles are referenced in a control using an XAML markup extension. You saw markup extensions in use in Chapter 5—when working with data binding in Silverlight, you set a control's property using the form {Binding, <path>. To reference the sample FormLabel style from your TextBlock, the syntax would look as follows:

<TextBlock Text="Age" Grid.Row="2" Style="{StaticResource FormLabel}"/>

Let's give styles a try, starting with defining styles at the page level.

Try It Out: Using Styles As Static Resources

In this exercise, you will define the styles as a static resource at the page level, using Expression Blend. The application will have a very simple UI, so you can focus on styles.

  1. In Expression Blend, create a new Silverlight 4 Application + Website named Ch12_Styles.

  2. Double-click the StackPanel control in the Toolbox to add a StackPanel. With the StackPanel selected, reset the Width and Height property so the StackPanel will automatically resize. Next, double-click the StackPanel in the Objects and Timeline panel so it is selected (you should see the border change around the StackPanel item). With the StackPanel selected, add two TextBox and two Button controls to the StackPanel. The Objects and Timeline panel should appear as shown in Figure 12-13.

    The controls for the application in the Objects and Timeline panel

    Figure 12.13. The controls for the application in the Objects and Timeline panel

    The XAML at this point should appear as follows:

    <Grid x:Name="LayoutRoot" Background="White" >
       <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
          <TextBox Text="TextBox" TextWrapping="Wrap"/>
          <TextBox Text="TextBox" TextWrapping="Wrap"/>
          <Button Content="Button"/>
          <Button Content="Button"/>
       </StackPanel>
    </Grid>
  3. Run the application. As shown in Figure 12-14, at this point, it really is nothing special. Now you'll use Silverlight styles to spice up its appearance.

    Initial Silverlight application without styles

    Figure 12.14. Initial Silverlight application without styles

  4. First, you need to build your Silverlight styles. Select the first TextBox in the Objects and Timeline panel and select Object

    Initial Silverlight application without styles
    The Create Style Resource dialog box

    Figure 12.15. The Create Style Resource dialog box

    At this point, you may notice a few changes:

    • The Objects and Timeline panel now contains the style object, but all of the form objects are no longer visible. At the top of the Objects and Timeline panel, you will see an up arrow with the text TextBoxStyle (TextBox Style) to its right. If you hover the mouse over the arrow, you will see a message that reads "Return scope to [UserControl]," as shown in Figure 12-16. Clicking this arrow will return you to the Objects and Timeline panel that you have grown used to, with the different form objects showing.

      Click the arrow next to the style name to see the controls in the UserControl's scope listed in the Objects and Timeline panel.

      Figure 12.16. Click the arrow next to the style name to see the controls in the UserControl's scope listed in the Objects and Timeline panel.

    • A new breadcrumb appears at the top of the artboard, as shown in Figure 12-17. The breadcrumb provides another way for you to navigate back to normal design mode.

      A new breadcrumb allows you to navigate back to normal design mode.

      Figure 12.17. A new breadcrumb allows you to navigate back to normal design mode.

    • The XAML has changed. A new <UserControl.Resources> section has been added, and the first TextBox has an added Style="{StaticResource TextBoxStyle}" attribute, as follows:

      <UserControl.Resources>
         <Style x:Key="TextBoxStyle" TargetType="TextBox"/>
      </UserControl.Resources>
      
      <Grid x:Name="LayoutRoot" Background="White" >
         <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
      <TextBox Text="TextBox" TextWrapping="Wrap"
               Style="{StaticResource TextBoxStyle}"/>
            <TextBox Text="TextBox" TextWrapping="Wrap"/>
            <Button Content="Button"/>
            <Button Content="Button"/>
         </StackPanel>
      </Grid>
  5. Next, you will set the different style attributes for your TextBoxStyle. Make certain that the TextBoxStyle is still in the Objects and Timeline panel, and from the Properties panel, set the following properties:

    • FontSize: 22

    • FontFamily: Trebuchet MS

    • Foreground: #FFFF0000

    • Margin: 5

    If you now examine the XAML, you will see that Expression Blend has added a number of Setter elements to the TextBoxStyle, as follows:

    <UserControl.Resources>
       <Style x:Key="TextBoxStyle" TargetType="TextBox">
          <Setter Property="FontSize" Value="22"/>
          <Setter Property="FontFamily" Value="Trebuchet MS"/>
          <Setter Property="Foreground" Value="#FFFF0000"/>
          <Setter Property="Margin" Value="5"/>
       </Style>
    </UserControl.Resources>
  6. Click the up arrow in the Objects and Timeline panel to return to the UserControl, and highlight the first Button control you added. With it selected, choose Object

    A new breadcrumb allows you to navigate back to normal design mode.
  7. This will create the new style ButtonStyle of TargetType Button and will add the Style attribute to the first button on your form. With the ButtonStyle selected, set the following properties:

    • FontSize: 20

    • FontFamily: Trebuchet MS

    • FontWeight: Bold

    • Width: 200

    • Margin: 5

    • Foreground: #FF0000FF

    With these properties set, your XAML will be updated to add the new Setter elements to the ButtonStyle style, as follows:

    <UserControl.Resources>
       <Style x:Key="TextBoxStyle" TargetType="TextBox">
          <Setter Property="FontSize" Value="22"/>
          <Setter Property="FontFamily" Value="Trebuchet MS"/>
          <Setter Property="Foreground" Value="#FFFF0000"/>
          <Setter Property="Margin" Value="5"/>
       </Style>
       <Style x:Key="ButtonStyle" TargetType="Button">
          <Setter Property="FontSize" Value="20"/>
          <Setter Property="FontFamily" Value="Trebuchet MS"/>
          <Setter Property="FontWeight" Value="Bold"/>
          <Setter Property="Width" Value="200"/>
          <Setter Property="Foreground" Value="#FF0000FF"/>
          <Setter Property="Margin" Value="5"/>
       </Style>
    </UserControl.Resources>

    Now you have two styles defined, and two of your controls are set to these styles. Next, you need to set the style for your other controls.

  8. Return to the UserControl in the Objects and Timeline panel and select the second TextBox control. Select Object

    A new breadcrumb allows you to navigate back to normal design mode.
  9. Select the second Button control and select Object

    A new breadcrumb allows you to navigate back to normal design mode.

    Your XAML should now look as follows:

    <UserControl.Resources>
       <Style x:Key="TextBoxStyle" TargetType="TextBox">
          <Setter Property="FontSize" Value="22"/>
          <Setter Property="FontFamily" Value="Trebuchet MS"/>
          <Setter Property="Foreground" Value="#FFFF0000"/>
          <Setter Property="Margin" Value="5"/>
       </Style>
       <Style x:Key="ButtonStyle" TargetType="Button">
          <Setter Property="FontSize" Value="20"/>
          <Setter Property="FontFamily" Value="Trebuchet MS"/>
          <Setter Property="FontWeight" Value="Bold"/>
          <Setter Property="Width" Value="200"/>
          <Setter Property="Foreground" Value="#FF0000FF"/>
          <Setter Property="Margin" Value="5"/>
       </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" >
       <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
          <TextBox Text="TextBox" TextWrapping="Wrap"
             Style="{StaticResource TextBoxStyle}"/>
          <TextBox Text="TextBox" TextWrapping="Wrap"
             Style="{StaticResource TextBoxStyle}"/>
          <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
          <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
       </StackPanel>
    </Grid>
  10. Run the application. The form now appears as shown in Figure 12-18.

    Silverlight application with styles Applied

    Figure 12.18. Silverlight application with styles Applied

    Now, let's say that you want to change the width of the text boxes in your application. Currently, their width is automatically set, but you would like to change them to a fixed width of 400 pixels. If you were using inline properties, as in the first two exercises in this chapter, you would need to set the property for each TextBox control in your application. However, since you are using Silverlight styles, you can simply change the TextBoxStyle, and all TextBox controls assigned to that style will be updated automatically. Let's see how this works.

  11. To modify the TextBoxStyle property from Expression Blend, click the Resources panel. When you expand the UserControl item, you will see your two styles listed. To the right of TextBoxStyle, you will see an Edit Resource button, as shown in Figure 12-19. Click this button, and you will see that you have returned to the TextBoxStyle's design scope.

    Resources panel showing the TextBoxStyle

    Figure 12.19. Resources panel showing the TextBoxStyle

    In the Properties panel, set the Width property of the TextBoxStyle to 400. Then click the up arrow in the Objects and Timeline panel to return to the UserControls scope.

    Your XAML should now look as follows:

    <Style x:Key="TextBoxStyle" TargetType="TextBox">
       <Setter Property="FontSize" Value="22"/>
       <Setter Property="FontFamily" Value="Trebuchet MS"/>
       <Setter Property="Foreground" Value="#FFFF0000"/>
       <Setter Property="Margin" Value="5"/>
       <Setter Property="Width" Value="400"/>
    </Style>
  12. Run the application to confirm that the width of both text boxes has been updated, as shown in Figure 12-20.

    The application with the updated TextBoxStyle

    Figure 12.20. The application with the updated TextBoxStyle

This exercise showed how Silverlight styles can be used as an alternative to defining styles inline. As you can see, this approach provides for much cleaner XAML and also greatly improves the ease of maintaining your application.

Defining Styles at the Application Level

In the previous example, you defined the styles locally, within your UserControl. If you have multiple UserControl components that you would like to share styles, you can define the styles at the application level. As far as the controls are concerned, there is absolutely no difference. You still indicate the style for the control using the Style="{StaticResource StyleName}" extended attribute. What does change is where the styles are defined.

In the preceding example, your styles were defined within the <UserControl.Resources> element on the UserControl itself, as follows:

<UserControl.Resources>
   <Style x:Key="TextBoxStyle" TargetType="TextBox">
      <Setter Property="FontSize" Value="22"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="Foreground" Value="#FFFF0000"/>
      <Setter Property="Margin" Value="5"/>
      <Setter Property="Width" Value="400"/>
   </Style>
   <Style x:Key="ButtonStyle" TargetType="Button">
      <Setter Property="FontSize" Value="20"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Width" Value="200"/>
      <Setter Property="Foreground" Value="#FF0000FF"/>
      <Setter Property="Margin" Value="5"/>
   </Style>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White" >
   <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
      <TextBox Text="TextBox" TextWrapping="Wrap"
         Style="{StaticResource TextBoxStyle}"/>
      <TextBox Text="TextBox" TextWrapping="Wrap"
         Style="{StaticResource TextBoxStyle}"/>
      <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
      <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
   </StackPanel>
</Grid>

In order to define the styles at the application level, instead of defining the styles in the <UserControl.Resources>, you move them to the App.xaml file within the element <Application.Resources>, as follows:

<Application.Resources>
    <Style x:Key="TextBoxStyle" TargetType="TextBox">
        <Setter Property="FontSize" Value="22"/>
        <Setter Property="FontFamily" Value="Trebuchet MS"/>
        <Setter Property="Foreground" Value="#FFFF0000"/>
        <Setter Property="Margin" Value="5"/>
        <Setter Property="Width" Value="400"/>
    </Style>
    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="FontFamily" Value="Trebuchet MS"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Width" Value="200"/>
        <Setter Property="Foreground" Value="#FF0000FF"/>
        <Setter Property="Margin" Value="5"/>
    </Style>
</Application.Resources>

That is all there is to it. Again, there are no changes at all to the controls themselves. For example, to use these styles on your UserControl, the XAML would still look like the following:

<Grid x:Name="LayoutRoot" Background="White" >
    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <TextBox Text="TextBox" TextWrapping="Wrap"
            Style="{StaticResource TextBoxStyle}"/>
        <TextBox Text="TextBox" TextWrapping="Wrap"
            Style="{StaticResource TextBoxStyle}"/>
        <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
        <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
    </StackPanel>
</Grid>

Merged Resource Dictionaries

A new feature as of Silverlight 4 is the ability to place your style definitions in external files called Merged Resource Dictionaries. As I have discussed in this chapter, you can define styles at the document or application level. If defining in the application level, your styles must be placed in the App.xaml file. This can result in a very large App.xaml. In Silverlight 4, you can now place your style definitions in external files and simply reference them in your application. An additional benefit from this change is that you can now create styles that can be easily reused between your applications, by simply copying the style resource files to your new solution. An example of using Merged Resource Dictionaries is seen the following code.

You can add a Resource Dictionary to a Silverlight application in Visual Studio by right-clicking on your project in the Solution Explorer and selecting Add New Item. On the Add New Item screen select the template named Silverlight Resource Dictionary and enter a name for the dictionary as shown in Figure 12-21.

Adding a Resource Dictionary

Figure 12.21. Adding a Resource Dictionary

You can then add your style information to the resource dictionary as the following code displays.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style x:Key="Heading1" TargetType="TextBlock">
        <Setter Property="FontSize" Value="22" />
        <Setter Property="Foreground" Value="Silver" />
    </Style>

    <Style x:Key="Heading2" TargetType="TextBlock">
        <Setter Property="FontSize" Value="18" />
    </Style>

</ResourceDictionary>

Finally, to use the resource dictionary in your application, you need to add an entry in the ResourceDictionary.MergedDictionaries section, as shown in the following code. Once you have added the entry for the ResourceDictionary, you can then use the styles as normal.

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Heading 1" Style="{StaticResource Heading1}" />
  <TextBlock Text="Heading 2" Style="{StaticResource Heading2}" />
</StackPanel>

Silverlight Style Hierarchy

As I mentioned earlier in the chapter, Silverlight styles are hierarchical. When a control has a style set, Silverlight will first look for the style at the local level, within the document's <UserControl.Resources>. If the style is found, Silverlight will look no further. If the style is not found locally, it will look at the application level. If the style is not found there, an XamlParseException will be thrown.

In addition to locally defined styles overriding application-level styles, any properties that are defined inline in the control element itself will override properties within the style. For example, consider the following XAML:

<UserControl.Resources>
    <Style x:Key="TextBoxStyle" TargetType="TextBox">
        <Setter Property="FontSize" Value="22"/>
        <Setter Property="FontFamily" Value="Trebuchet MS"/>
        <Setter Property="Foreground" Value="#FFFF0000"/>
        <Setter Property="Margin" Value="5"/>
        <Setter Property="Width" Value="400"/>
    </Style>
    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="FontFamily" Value="Trebuchet MS"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Width" Value="200"/>
        <Setter Property="Foreground" Value="#FF0000FF"/>
        <Setter Property="Margin" Value="5 "/>
    </Style>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White" >
    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <TextBox Text="TextBox" TextWrapping="Wrap"
            Style="{StaticResource TextBoxStyle}" FontSize="10"/>
        <TextBox Text="TextBox" TextWrapping="Wrap"
            Style="{StaticResource TextBoxStyle}"/>
        <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
        <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
    </StackPanel>
</Grid>

Both TextBox controls are set to the TextBoxStyle style; however, the first TextBox has an inline property defined for FontSize. Therefore, when you run the XAML, it will appear as shown in Figure 12-22.

An example of inline properties overriding style properties

Figure 12.22. An example of inline properties overriding style properties

Notice that even though FontSize was defined inline, the control still picked up the remaining properties from TextBoxStyle. However, a locally defined style will prevent any properties from being applied from an application-level style.

Inheriting Styles Using BasedOn

A feature that first showed up in Silverlight 3 is the ability to create styles that are based on another style. This allows you to create base styles that can help organize and maintain your styles across your application. As an example, consider the following source. Notice there are three styles that are defined. BaseButtonStyle defines the base style, RedButton derives from BaseButtonStyle inheriting all properties from the base style including the FontSize, FontFamily, Margin and additionally sets the Foreground to Red. There is also a third style, RedButtonBigFont, that derives from the RedButton style, and overrides the FontSize.

<UserControl.Resources>
    <Style x:Key="BaseButtonStyle" TargetType="Button">
        <Setter Property="FontSize" Value="22" />
        <Setter Property="FontFamily" Value="Trebuchet MS" />
        <Setter Property="Margin" Value="5" />
    </Style>

    <Style x:Key="RedButton" TargetType="Button"
           BasedOn="{StaticResource BaseButtonStyle}">
        <Setter Property="Foreground" Value="Red" />
    </Style>

    <Style x:Key="RedButtonBigFont" TargetType="Button"
           BasedOn="{StaticResource RedButton}">
        <Setter Property="FontSize" Value="28" />
    </Style>

</UserControl.Resources>
<StackPanel x:Name="LayoutRoot">

    <Button Style="{StaticResource BaseButtonStyle}"
            Content="Base Button" />
    <Button Style="{StaticResource RedButton}"
            Content="Red Button" />
    <Button Style="{StaticResource RedButtonBigFont}"
            Content="Red Button Big Font" />

</StackPanel>

If you run this source, you will get the results shown in Figure 12-23. Notice that the Red Button has all of the attributes of the Base Button, but additionally has the font color red. Similarly, the "Red Button Big Font" button has all the attributes of the Red Button, but overrides the FontSize to have a larger font.

Result of Derived Styles Using BasedOn

Figure 12.23. Result of Derived Styles Using BasedOn

Implicit Styles

Prior to Silverlight 4, all styles had to contain both a key and a TargetType. A new feature present in Silverlight 4 is the ability to create an implicit style that will be applied to all controls of a given TargetType automatically. This means that if you know that you want the default look of all your Button controls, you can create an implicit style that will be applied to all buttons without having to set the Style property on the actual Button control definitions.

Consider the following example of a StackPanel that contains five buttons. The first four buttons simply have the base <Button /> definition, where the last Button also includes a style reference. Because the first four buttons do not have a style specified, they will all use the implicit Button style defined in UserControl.Resources. The last Button will not use any of the Style properties defined in the implicit style, however, since it has an explicit style specified. Instead, it will get its style from the OverrideStyle style. The result of the following example is shown in Figure 12-24.

<UserControl.Resources>
    <Style TargetType="Button">
        <Setter Property="FontSize" Value="10" />
        <Setter Property="Width" Value="200" />
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="Content" Value="Default Style" />
        <Setter Property="Margin" Value="5" />
    </Style>
    <Style x:Key="OverrideStyle" TargetType="Button">
        <Setter Property="FontSize" Value="14" />
        <Setter Property="Width" Value="300" />
        <Setter Property="FontWeight" Value="Bold" />
        <Setter Property="Content" Value="Overridden Style" />
    </Style>
</UserControl.Resources>

<StackPanel x:Name="LayoutRoot" Background="White">
    <Button />
    <Button />
    <Button />
    <Button />
    <Button Style="{StaticResource OverrideStyle}"  />
</StackPanel>
Result from usage of Implicit Styles

Figure 12.24. Result from usage of Implicit Styles

Summary

In this chapter, you looked at options for styling your Silverlight applications. You saw how to define style properties inline using both Visual Studio and Expression Blend. Then you explored defining styles with Silverlight styles, both at the document level and the application level. In the next chapter, you will look at using Expression Blend to define Silverlight transformations and animations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset