Try an online Silverlight class for free!
Additional Resources

Silverlight Controls

In this lesson of the Silverlight tutorial, you will learn...
  1. To implement various Silverlight controls included in the Silverlight download.
  2. To use additional Silverlight controls included in the Silverlight Software Development Kit (SDK).
  3. To use skins to apply a consistent look and feel to controls.
  4. To use data templates to modify the presentation behavior and appearance of controls.

Overview

Silverlight 2 includes a large palette of controls.

The sections below illustrate how to use the controls available in Silverlight as well as how to customize those controls.

Layout Controls

Silverlight includes three primary layout controls. Layout controls were introduced with Windows Presentation Foundation (WPF) and serve as a container for other controls where they are used to manage the layout, sizing, and positioning of their contained controls. The WPF layout controls that are available in Silverlight are described below.

Canvas Control

The Canvas layout control allows controls to be positioned at absolute X,Y coordinates. When controls are contained within a Canvas layout control, the contained controls use Canvas.Left and Canvas.Top properties to absolutely position the contained controls within the space of the containing Canvas control. The XAML markup listing below illustrates a Canvas control that contains a Rectangle with a gradient fill applied.

<UserControl x:Class="Canvas.Page" xmlns="http://schemas.microsoft.com/client/2007" 
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300">
 <Canvas x:Name="LayoutRoot" Background="White">
  <Rectangle Height="125" Width="161" Canvas.Left="153" Canvas.Top="99" Stroke="#FF000000">
   <Rectangle.Fill>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
     <GradientStop Color="#FF6A4D18"/>
     <GradientStop Color="#FFFFFFFF" Offset="1"/>
    </LinearGradientBrush>
   </Rectangle.Fill>
  </Rectangle>
 </Canvas>
</UserControl>

The figure below illustrates the result of the markup listing above as displayed in Safari:

StackPanel Control

The StackPanel control is a true dynamic layout control in that it dynamically manages the positioning, sizing, and layout of controls it contains.

Contained controls are "stacked" on top of each other as the name implies. The StackPanel control may be configured to stack controls horizontally or vertically. The XAML markup listing below illustrates use of the StackPanel control.

<UserControl x:Class="StackPanel.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300">
 <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
  <Button Height="Auto" Width="Auto" Content="Button"/>
  <Button Height="25.903" Width="400" Content="Button"/>
  <Button Height="25.903" Width="400" Content="Button"/>
  <Button Height="25.903" Width="400" Content="Button"/>
  <Button Height="25.903" Width="400" Content="Button"/>
  <Button Height="25.903" Width="400" Content="Button"/>
 </StackPanel>
</UserControl>

The figure below shows the results of the markup above as displayed in Internet Explorer:

Grid Control

The Grid control is used to layout controls in a table. The Grid control is very similar in functionality to an HTML table and consists of rows and columns.

To define a grid, you first use the RowDefinition and ColumnDefinition elements to define the size and number of each row and column. The Height and Width properties can contain:

  • An exact pixel value, for example:
    <RowDefinition Height="50" />
  • The keyword "auto", which will size the row or column to fit its contents. For example:
    <RowDefinition Height="auto" />
  • The star "*" value, which will size the row or column to take up all available space that is not taken up by other rows or columns. For example:
    <RowDefinition Height="*" />
  • The star "*" value, prefixed with a numeric value, which will size the row or column to take up a proportional space of the available width or height. For example, the RowDefinitions below will set up rows with a proportion of 2:3:1:
    <RowDefinition Height="2*" />
    <RowDefinition Height="3*" />
    <RowDefinition Height="1*" />

Let's look at some complete examples of the Grid layout control. The XAML markup listing shown below illustrates a simple example with three rows and three columns. Each row and column is proportionally the same size, as denoted by the "*" star notation for width and height:

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
 <Grid.RowDefinitions>
  <RowDefinition Height="*" />
  <RowDefinition Height="*" />
  <RowDefinition Height="*" />
 </Grid.RowDefinitions>
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="*" />
 </Grid.ColumnDefinitions>
 
 <TextBlock Text="Column 0, Row 0" Grid.Column="0" Grid.Row="0" />
 <TextBlock Text="Column 1, Row 1" Grid.Column="1" Grid.Row="1" />
 <TextBlock Text="Column 2, Row 2" Grid.Column="2" Grid.Row="2" />
</Grid>

The figure below shows the results of the markup above as displayed in Internet Explorer:

This next example of the Grid layout control uses a mix of pixel values and star "*" notation to create three rows. The first row is exactly 200 pixels high, the second and third rows will take up the remaining available height in a 2:1 ratio:

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
 <Grid.RowDefinitions>
  <RowDefinition Height="200" />
  <RowDefinition Height="2*" />
  <RowDefinition Height="*" />
 </Grid.RowDefinitions>
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="*" />
 </Grid.ColumnDefinitions>
 
 <TextBlock Text="Column 0, Row 0" Grid.Column="0" Grid.Row="0" />
 <TextBlock Text="Column 1, Row 1" Grid.Column="1" Grid.Row="1" />
 <TextBlock Text="Column 2, Row 2" Grid.Column="2" Grid.Row="2" />
</Grid>

The figure below shows the results of the markup above as displayed in Internet Explorer:

User Interface Controls

Silverlight 2 ships with a gamut of user interface controls that are used to gather data from and display data for users.

Border Control

The Silverlight Border control is used to dress up a portion of a Silverlight control by drawing a border around a section of the control. Each side of the border can be displayed or not displayed and controlled independent of the other sides and a background color may be selected.

Button Control

The Button control is one of the most commonly used Silverlight controls as it is the preferred method for users to submit data or perform other operations in an application. The most commonly used event associated with the Button control is the Click event.

Most controls and items used in Silverlight include either a Click event or a MouseLeftButtonUp event so that virtually any item in a Silverlight application can be treated as a button or simulate one.

Calendar Control

The Calendar control is used to display a selectable calendar to the user. The Calendar control accommodates month and year display modes and is completely customizable.

Checkbox Control

The Checkbox control provides the ability to select between three states based on the IsThreeState property. If IsThreeState is set to false, the Checkbox only toggles between true and false states. If IsThreeState is set to true, the Checkbox toggle between three states.

DatePicker Control

The DatePicker control is used to present the user a calendar for selecting a date value.

HyperlinkButton Control

The HyperlinkButton control is used to display a hyperlink on the Silverlight control. The HyperlinkButton control can be used as a hyperlink for navigation or email or as a button by assigning an event handler to the Click event.

Image Control

The Image control is used to display an image.

RadioButton Control

The RadioButton control is used to present a selection option to the user. Radio buttons are grouped using the GroupName property. The control allows for only one group member to be selected at a time.

RepeatButton Control

The RepeatButton control is used to continually repeat an action while the button is held down. The repeat delay and duration can be modified through properties of the RepeatButton control.

ScrollViewer Control

The ScrollViewer control serves as a container for other controls and is used to provide a view port for the contained control with the ability to scroll to view the entire contained control.

Slider Control

The Slider control is used to visually slide across a range of values and fire events based on the values encountered.

TextBlock Control

The TextBlock control is used to manage a string literal displayed to the user.

Textbox Control

The Textbox control is used to collect data from users.

ToggleButton Control

The ToggleButton appears as a typical Button control but functions as a Checkbox control. It allows the user to choose between two or three values.

Designing User Interfaces

The Silverlight design standards recommended by Microsoft follow the User Experience (UX) guidelines for Windows Vista. The UX guidelines are documented in the MSDN document entitled "Guidelines" located at http://msdn.microsoft.com/en-us/library/aa511440.aspx.

Skinning Controls and Templates

The controls shipped with WPF and Silverlight are created and assembled using a collection of shapes and images that are grouped together. These controls provided with WPF and Silverlight can be "ungrouped" or broken down to gain access to the smaller collective parts. Each smaller part of a control can be modified to change its appearance. This is known as skinning the control.

To illustrate, the screenshot below shows a standard button in a Silverlight control in Expression Blend:

To skin a Silverlight control using Expression Blend, right-click the control and select Edit Control Parts (Template) > Edit a Copy from the context menu. The Edit a Copy option creates a copy of the control as a resource in the project and provides access to the collective parts of the control. When the Edit a Copy option is selected, the Create Style Resource dialog is displayed as shown in the figure below:

Clicking OK on the Create Style Resource dialog displays the new control template in the Objects and Timeline subpanel. Select any items in the Objects and Timeline subpanel to customize the appearance of the control. As an example, the standard button control was modified to appear as shown in the figure below:

Bear in mind, as shown in the figure above, that modifications to a control template could affect the behavior of the control. In the example above, a gradient layer was removed and, hence, some of the animations built into a standard button control are no longer valid and were automatically removed. Click the Return Scope button to exit the template editing mode and begin using the customized ("skinned") control.

By modifying the display of a control, Expression Blend adds custom XAML behind the scenes to render the custom control. The result of the modification made above is shown in the XAML listing below.

<UserControl x:Class="SCSkinning.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
 <UserControl.Resources>
  <Style x:Key="myButton" TargetType="Button">
   <Setter Property="IsEnabled" Value="true"/>
   <Setter Property="IsTabStop" Value="true"/>
   <Setter Property="Background" Value="#FF003255"/>
   <Setter Property="Foreground" Value="#FF313131"/>
   <Setter Property="MinWidth" Value="5"/>
   <Setter Property="MinHeight" Value="5"/>
   <Setter Property="Margin" Value="0"/>
   <Setter Property="HorizontalContentAlignment" Value="Center"/>
   <Setter Property="VerticalContentAlignment" Value="Center"/>
   <Setter Property="Cursor" Value="Arrow"/>
   <Setter Property="TextAlignment" Value="Left"/>
   <Setter Property="TextWrapping" Value="NoWrap"/>
   <Setter Property="FontSize" Value="11"/>
   <Setter Property="Template">
    <Setter.Value>
     <ControlTemplate TargetType="Button">
      <Grid>
       <Grid.Resources>
        <Color x:Key="LinearBevelLightStartColor">#FCFFFFFF</Color>
        <Color x:Key="LinearBevelLightEndColor">#F4FFFFFF</Color>
        <Color x:Key="LinearBevelDarkStartColor">#E0FFFFFF</Color>
        <Color x:Key="LinearBevelDarkEndColor">#B2FFFFFF</Color>
        <Color x:Key="MouseOverLinearBevelDarkEndColor">#7FFFFFFF</Color>
        <Color x:Key="HoverLinearBevelLightStartColor">#FCFFFFFF</Color>
        <Color x:Key="HoverLinearBevelLightEndColor">#EAFFFFFF</Color>
        <Color x:Key="HoverLinearBevelDarkStartColor">#D8FFFFFF</Color>
        <Color x:Key="HoverLinearBevelDarkEndColor">#4CFFFFFF</Color>
        <Color x:Key="CurvedBevelFillStartColor">#B3FFFFFF</Color>
        <Color x:Key="CurvedBevelFillEndColor">#3CFFFFFF</Color>
        <SolidColorBrush x:Key="BorderBrush" Color="#FF000000"/>
        <SolidColorBrush x:Key="AccentBrush" Color="#FFFFFFFF"/>
        <SolidColorBrush x:Key="DisabledBrush" Color="#A5FFFFFF"/>
        <LinearGradientBrush x:Key="FocusedStrokeBrush" EndPoint="0.5,1" StartPoint="0.5,0">
         <GradientStop Color="#B2FFFFFF" Offset="0"/>
         <GradientStop Color="#51FFFFFF" Offset="1"/>
         <GradientStop Color="#66FFFFFF" Offset="0.325"/>
         <GradientStop Color="#1EFFFFFF" Offset="0.325"/>
        </LinearGradientBrush>
       </Grid.Resources>
       <vsm:VisualStateManager.VisualStateGroups>
        <vsm:VisualStateGroup x:Name="CommonStates">
         <vsm:VisualStateGroup.Transitions>
          <vsm:VisualTransition Duration="0:0:0.2" To="MouseOver"/>
          <vsm:VisualTransition Duration="0:0:0.1" To="Pressed"/>
         </vsm:VisualStateGroup.Transitions>
         <vsm:VisualState x:Name="Normal"/>
         <vsm:VisualState x:Name="MouseOver">
          <Storyboard/>
         </vsm:VisualState>
         <vsm:VisualState x:Name="Pressed">
          <Storyboard>
           <DoubleAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DownStroke" Storyboard.TargetProperty="Opacity">
            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
           </DoubleAnimationUsingKeyFrames>
          </Storyboard>
         </vsm:VisualState>
         <vsm:VisualState x:Name="Disabled">
          <Storyboard>
           <DoubleAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DisabledVisual" Storyboard.TargetProperty="Opacity">
            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
           </DoubleAnimationUsingKeyFrames>
          </Storyboard>
         </vsm:VisualState>
        </vsm:VisualStateGroup>
        <vsm:VisualStateGroup x:Name="FocusStates">
         <vsm:VisualState x:Name="Focused">
          <Storyboard>
           <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0">
             <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
             </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
           </ObjectAnimationUsingKeyFrames>
          </Storyboard>
         </vsm:VisualState>
         <vsm:VisualState x:Name="Unfocused">
          <Storyboard>
           <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0">
             <DiscreteObjectKeyFrame.Value>
              <Visibility>Collapsed</Visibility>
             </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
           </ObjectAnimationUsingKeyFrames>
          </Storyboard>
         </vsm:VisualState>
        </vsm:VisualStateGroup>
       </vsm:VisualStateManager.VisualStateGroups>
       <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" RadiusX="4" RadiusY="4"/>
       <Grid Margin="2" x:Name="CurvedBevelScale">
        <Grid.RowDefinitions>
         <RowDefinition Height="7*"/>
         <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>
        <Path Margin="3,0,3,0" x:Name="CurvedBevel" Stretch="Fill" Data="F1 M 0,0.02 V 0.15 C 0.15,0.22 0.30,0.25 0.50,0.26 C 0.70,0.26 0.85,0.22 1,0.15 V 0.02 L 0.97,0 H 0.02 L 0,0.02 Z">
         <Path.Fill>
          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
           <GradientStop Color="{StaticResource CurvedBevelFillStartColor}" Offset="0"/>
           <GradientStop Color="{StaticResource CurvedBevelFillEndColor}" Offset="1"/>
          </LinearGradientBrush>
         </Path.Fill>
        </Path>
       </Grid>
       <Rectangle Margin="1" x:Name="Accent" Stroke="{StaticResource AccentBrush}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
       <Grid x:Name="FocusVisual" Visibility="Collapsed">
        <Rectangle Margin="2" Stroke="{StaticResource AccentBrush}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Stroke="{TemplateBinding Background}" StrokeThickness="2" RadiusX="3" RadiusY="3"/>
        <Rectangle Stroke="{StaticResource FocusedStrokeBrush}" StrokeThickness="2" RadiusX="3" RadiusY="3"/>
       </Grid>
       <Grid x:Name="DownStroke" Opacity="0">
        <Rectangle Margin="1,2,1,1" Opacity="0.05" Stroke="{TemplateBinding Background}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Margin="1,1.75,1,1" Opacity="0.05" Stroke="{TemplateBinding Background}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Margin="1,1.5,1,1" Opacity="0.05" Stroke="{TemplateBinding Background}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Margin="1,1.25,1,1" Opacity="0.05" Stroke="{TemplateBinding Background}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Margin="1" Opacity="1" Stroke="{TemplateBinding Background}" StrokeThickness="1" RadiusX="3" RadiusY="3"/>
        <Rectangle Margin="1" StrokeThickness="1" RadiusX="4" RadiusY="4">
         <Rectangle.Stroke>
          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
           <GradientStop Color="#A5FFFFFF" Offset="0"/>
           <GradientStop Color="#FFFFFFFF" Offset="1"/>
          </LinearGradientBrush>
         </Rectangle.Stroke>
        </Rectangle>
       </Grid>
       <ContentPresenter Margin="4,5,4,4" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" TextAlignment="{TemplateBinding TextAlignment}" TextDecorations="{TemplateBinding TextDecorations}" TextWrapping="{TemplateBinding TextWrapping}"/>
       <Rectangle x:Name="DisabledVisual" IsHitTestVisible="false" Opacity="0" Fill="{StaticResource DisabledBrush}" RadiusX="4" RadiusY="4"/>
      </Grid>
     </ControlTemplate>
    </Setter.Value>
   </Setter>
  </Style>
 </UserControl.Resources>
 <Grid x:Name="LayoutRoot" Background="White">
  <Button Height="34" HorizontalAlignment="Stretch" Margin="33,41,193,0" Style="{StaticResource myButton}" VerticalAlignment="Top" Content="click me!"/>
 </Grid>
</UserControl>

Notice in the XAML listing above that the style created has a key of myButton assigned. The style is applied to a control using the Style attribute and the StaticResource directive.

To make the style more reusable, the style can be moved into the App.xaml file and then applied to any control within the Silverlight application. Alternatively, when the template copy of the control is created, the template can be directed to be created for the Application instead of for the Document.

Visual State Manager (VSM)

Nearly all Silverlight controls exist in multiple states, or appearances, while they are instantiated. For example, a Button control includes a default state, or appearance, that is displayed when the button is first displayed. When a user moves the mouse pointer over a Button control, it, by default, changes color somewhat to highlight the button. The highlighted appearance represents a different visual state that the Button control exists in. Each type of control may include several visual states. Expression Blend includes an interface, called the Visual State Manager (VSM), for easily managing the various visual states of a control.

To access the VSM, open a Silverlight control in Expression Blend. Right-click on the control that visual states should be modified for and select Edit Control Parts (Template) > Edit a Copy to create a template copy of the control. Notice the VSM highlighted in the figure below.

In order to use the VSM, select the desired state to change from the VSM panel, modify the control with that state selected, and then save the control. The Visual State Manager also provides access to the visual states of a control programmatically.

User Controls and Custom Controls

Although Silverlight has a wide range of buit-in controls, some software may require customized controls that go beyond what is provided in the core Silverlight toolbox. A design goal of WPF and Silverlight is to enable developers to extend the built-in controls with their own custom-built controls. The two major ways to extend Silverlight controls are User Controls and Custom Controls .

User Controls are containers which hold one or more other controls within their boundaries. They are generally easy to create because you use XAML to define their User Interface, and they provide a code-behind file so you can add business logic and other functionality.

Custom Controls can be used to extend functionality of existing controls through inheritence. This is handy when you need to extend the default behavior of a built-in Silverlight control. For example, perhaps an application needs an Auto-Complete TextBox control that suggests words as the user types. Custom Controls also allow for changing their appearance with a "skin" that defines their look.

Implementing User Controls

User Controls are useful for the following scenarios:

  • We have a portion of a user interface that we want to re-use in several parts of our application. For example, maybe our application requires that Address information (Address Line 1, Address Line 2, City, State, Zip) be entered on several screens. We could create a user control that contains TextBlock and TextBox controls for "Address Entry" and then plant that User Control on each page that needs it.
  • We have a complicated portion of a user interface and business logic which we want to separate out to reduce complexity. For example, perhaps your application requires a Map Control which reads imagery from Virtual Earth. Instead of mixing this logic into your main UI, you can abstract it into a control so that the code is easier to maintain.

User Control Template

Silverlight Tools for Visual Studio provides a template for creating UserControls. We simply need to select "Add New Item" from the Project menu in Visual Studio, and select this template from the Add New Item Dialog:

This creates a new .xaml file for our User Control interface (shown below), and a new .xaml.cs (or .xaml.vb for VB.NET) file for adding code and responding to events:

<UserControl x:Class="AthleteManager.ucLoginStatus"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</UserControl>

We can then design our User Interface for the control by adding controls into the XAML, either in the Visual Studio XAML editor or inside Expression Blend (to open in Blend, right-click the XAML file in Solution Explorer and select "Open in Expression Blend." Additionally, we can add business and UI logic to the code behind file, being sure to use the "public" modifier to mark any methods that we want accessible from pages which consume our user control.

Adding User Controls to a User Interface

There are three ways we can add an instance of a User Control to a page:

  1. Using Expression Blend, we can open the page we want to add our User Control to. Then, we select the Asset Library icon (the last icon in the Blend Toolbox) and select the Custom Controls tab (see below). We can then "paint" one or more instances of the user control onto the page by clicking and dragging the mouse on the design surface.
  2. We can directly add a User Control in XAML using the Visual Studio XAML editor. This is a two-step process:
    • First we need to register the user control on the page. We do this by adding an XML Namespace (xmlns) attribute to the top of the page, within the <UserControl> element. This "xmlns" reference includes a friendly prefix which you will later use to include the control in the page content, and references the .Net namespace which contains the user control.
      • For example, if we wish to prefix our user control references with "AthleteManager", and the user control definition exists in a namespace named "AthleteManager", then we would add the following xmlns attribute to the UserControl element:
        xmlns:AthleteManager="clr-namespace:AthleteManager"
    • Next, we instantiate the user control on the page using the xmlns prefix we created in the previous step and the user control class name.
      • The example code below instantiates a control named ucLoginStatus within the AthleteManager namespace, and assigns it a variable id of "ucLoginStatus1":
        <AthleteManager:ucLoginStatus x:Name="ucLoginStatus1" />

"Everything" is a User Control

It's interesting to point out that every UI element that you create using the Silverlight Tools for Visual Studio is a User Control! Even the Page.xaml that is initially created inside a Silverlight project is a User Control. We can verify this by examining Page.xaml in a freshly created Silverlight project:

<UserControl x:Class="MySilverlightApp.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</UserControl>

This default Page.xaml User Control is instantiated inside App.xaml.cs (or App.xaml.vb for VB.NET). This is how our initial User Interface gets displayed by the Silverlight project.

private void Application_Startup(object sender, StartupEventArgs e)
        {
            // Load the main control
            this.RootVisual = new Page();
        }

Custom Controls

Custom Controls are similar to User Controls, but are more easily styled by designers (and are a bit more work to create). You might choose to create a Custom Control instead of a User Control if you are creating a generic, reusable control that will be used across many projects. For example, perhaps you are a 3rd Party control developer and want to create a charting control to resell to other developers.

The steps to creating a Custom Control are as follows: NOTE: We will explore all of the steps in detail in the Lab at the end of this module.

  1. Create a class that inherits from Control, or from an existing Silverlight control class.
    public class BlinkBox:Control
    {
    }
  2. Create a default skin, named generic.xaml and set its build action to Resource. This xaml file contains the default look of your control, as it will appear without any additional styling applied. As a convention, we should place the generic.xaml file inside a subdirectory called "Themes" in the project. You will also need to expose the style properties that you want to allow the designer to style using the "{TemplateBinding}" directive for each property you want to allow styling on. In the example below, several Font properties are exposed for styling using the TemplateBinding directive.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:MyCustomControls">
        <Style TargetType="local:BlinkBox">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:BlinkBox">
                        <Grid>
                            <TextBlock x:Name="txtContent" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}"
                                Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" 
                                FontStretch="{TemplateBinding FontStretch}" FontStyle="{TemplateBinding FontStyle}"
                          />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
  3. In the Constructor for the custom control class, define the style type that will be used to uniquely identify this control's style. (Remember that, when skinning controls, we need to specify a control type and a key for each style, as in <Style x:Key="myButtonStyle" TargetType="Button">):
    public BlinkBox()
    {
     // DefaultStyleKey defines type used when defining style keys:
     DefaultStyleKey = typeof(BlinkBox);
    }
  4. Define any Properties for the control, using the DependencyProperty type. Dependency Properties allow for styling, templating, data-binding and animation of property values. Dependency Properties must have a matching public property for accessing the dependency property. In the example below, we define a Dependency Property for handling setting the Text property of a custom control. Note that the get/set property accessors merely wrap the dependency property.
    public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register("Text", typeof(string), typeof(BlinkBox),
    new PropertyMetadata("", new PropertyChangedCallback((obj, args) =>
    {
     // handle any logic here for setting Text
    })));
    
    public string Text
    {
     get
     {
      return GetValue(TextProperty) as string;
     }
     set
     {
      SetValue(TextProperty, value);
     }
    }

Once a Custom Control is created, it is referenced and used in the same way as a User Control - you can use Expression Blend's Asset Library to drag/drop Custom Controls onto the design surface. Or, you can use an xmlns reference in your pages to manually add Custom Controls into XAML.

Exercise: Create the Login Dialog

Duration: 45 to 60 minutes.

In this exercise, you will design a login dialog using some common Silverlight controls.

  1. Open Visual Studio 2008 and select New Project from the File menu.
  2. In the Visual C# category, select Silverlight, and then select Silverlight Application.
  3. Name the solution "AthleteManagerControls"
    1. In the following dialog leave the default option to add a new ASP.NET Web Project to the solution selected and click OK.
  4. We will now create a simple Web Service to "authenticate" a user.
  5. Right-click the "AthleteManagerControls.Web" project and select Add > New Item.
  6. Select the Silverlight-Enabled WCF Service template from the Silverlight category and name the service "AthleteService.svc."
  7. Add the following new method to the AthleteService.svc.cs file to mock a login:
    [OperationContract]
    public bool AuthenticateUser(string username, string password)
    {
     if (username == "admin" && password == "password")
      return true;
     else
      return false;
    }
  8. In the Silverlight project, right-click the project and select Add Service Reference.
    1. Click the Discover button and then select the AthleteService web service
    2. In the Namespace box, enter "AthleteService" and click OK.
  9. In the Silverlight project, right-click the Page.xaml file and open it in Expression Blend.
  10. Change the Grid layout container to a Canvas.
  11. Size the canvas large enough to accommodate the display of athlete information (approximately 600 X 450 or larger).
  12. Add another canvas to the design surface. This canvas should be sized smaller and will serve as the login dialog as shown in the figure below:
  13. Add TextBlocks, a TextBox, a PasswordBox and Buttons to the smaller canvas to serve as the Login dialog.
  14. Add a TextBlock to the bottom of the dialog that will display informational messages to the user.
  15. Make sure that this TextBlock has a name assigned to it.
  16. The resulting design should resemble the following figure:
  17. Make sure to assign a name to the login dialog canvas.
  18. Your resulting XAML in Page.xaml should look similar to what is below:
    <UserControl x:Class="AthleteManagerControls.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300">
     <UserControl.OpacityMask>
      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
       <GradientStop Color="#FF4C4B48"/>
       <GradientStop Color="#FFFFFFFF" Offset="1"/>
      </LinearGradientBrush>
     </UserControl.OpacityMask>
     <Canvas x:Name="LayoutRoot">
      <Canvas.Background>
       <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF558092"/>
        <GradientStop Color="#FFFFFFFF" Offset="0.821"/>
       </LinearGradientBrush>
      </Canvas.Background>
      <Canvas Height="200" Width="584" Canvas.Left="8" Canvas.Top="8" Background="#FF558092" x:Name="canvasLogin">
       <TextBlock Height="Auto" Width="Auto" Canvas.Left="12" Canvas.Top="10" Foreground="#FFEDEEC5" TextWrapping="Wrap" Text="user name:"/>
       <TextBlock Height="Auto" Width="Auto" Foreground="#FFEDEEC5" TextWrapping="Wrap" Text="password:" Canvas.Left="12" Canvas.Top="36.537"/>
       <TextBox Height="Auto" Width="480.902" Canvas.Left="95.098" Canvas.Top="10" Text="" x:Name="txtUserName" Foreground="#FF183541"/>
       <PasswordBox Height="Auto" Width="480.902" Canvas.Left="95.098" Canvas.Top="40.537" x:Name="txtPassword" Foreground="#FF183541"/>
       <Button Height="30" Width="169.098" Canvas.Left="406.902" Canvas.Top="71.074" Content="log me in" x:Name="btnLogin" Click="btnLogin_Click"/>
       <TextBlock Height="37" x:Name="tbLoginStatus" Width="564" Canvas.Left="12" Canvas.Top="125" Foreground="Orange" TextWrapping="Wrap"/>
       <CheckBox Height="21" Width="151" Canvas.Left="12" Canvas.Top="80.074" Content="Remember Me" x:Name="chkRememberMe"/>
      </Canvas>
     </Canvas>
    </UserControl>
  19. Next, we will add some functionality to the login dialog.
  20. Close Blend and return to Visual Studio.
  21. In the page constructor, assign a callback method to the AuthenticateUserCompleted event of the Web service reference (your method may be named differently if you didn't name it as the example).
  22. Next, add an event handler to the login button Click event. Pass the username and password supplied by the UI to the AuthenticateUserAsync Web service method.
  23. In the AuthenticateUserCompleted callback method, write code to determine if the user was authenticated or not and notify the user. The code behind example code should resemble the following.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    namespace AthleteManagerControls
    {
     public partial class Page : UserControl
     {
      AthleteManagerControls.AthleteService.AthleteServiceClient svc = new AthleteManagerControls.AthleteService.AthleteServiceClient();
      
      public Page()
      {
       InitializeComponent();
       
       svc.AuthenticateUserCompleted += new EventHandler<AthleteManagerControls.AthleteService.AuthenticateUserCompletedEventArgs>(svc_AuthenticateUserCompleted);
       btnLogin.Click += new RoutedEventHandler(btnLogin_Click);
      }
      
      void btnLogin_Click(object sender, RoutedEventArgs e)
      {
       svc.AuthenticateUserAsync(txtUserName.Text, txtPassword.Password);
      }
      
      void svc_AuthenticateUserCompleted(object sender, AthleteManagerControls.AthleteService.AuthenticateUserCompletedEventArgs e)
      {
      if (e.Result)
      {
       System.Windows.Browser.HtmlPage.Window.Alert("Login successful");
      }
      else
      {
       System.Windows.Browser.HtmlPage.Window.Alert("Login Failed");
      }
     }
    }
    }
  24. You should now be able to test the login dialog successfully. Try testing it out by entering valid and invalid user credentials.

Exercise: Create a Login Status User Control

Duration: 30 to 45 minutes.

In this exercise, you will create a reusable User Control which will display the current login status of the user.

  1. Right-click the AthleteManager project in Solution Explorer and select Add/New Item. Select "Silverlight User Control" and name the control ucLoginStatus.xaml.
  2. Right-click ucLoginStatus.xaml in Solution Explorer and select "Open in Expression Blend."
  3. Resize the Grid container to about 175 pixels wide by 25 pixels high.
  4. In Blend, create a Rectangle with rounded corners that is the same height and width as the Grid container. Add a Radial Gradient for aesthetics.
  5. Add a TextBlock control centered on the rectangle and name the control txtStatus. Your final XAML should look similar to this:
    <UserControl x:Class="AthleteManager.ucLoginStatus"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="175" Height="25">
        <Grid x:Name="LayoutRoot" Width="176">
         <Rectangle Margin="1,1,1,1" Stroke="#FF000000" RadiusY="6" RadiusX="6">
          <Rectangle.Fill>
           <RadialGradientBrush>
            <GradientStop Color="#FFFFFFFF"/>
            <GradientStop Color="#FFFFEBA3" Offset="1"/>
           </RadialGradientBrush>
          </Rectangle.Fill>
         </Rectangle>
         <TextBlock Margin="9,5,11,6" Text="Status: Not Logged In" TextWrapping="Wrap" x:Name="txtStatus"/>
    
        </Grid>
    </UserControl>
      
  6. In the code-behind file (ucLoginStatus.xaml.cs), add a public property to change the login status displayed in the control:
      bool _isLoggedIn = false;
      public bool IsLoggedIn {
       get
       {
        return _isLoggedIn;
       }
       set
       {
        _isLoggedIn = value;
        if (_isLoggedIn)
         txtStatus.Text = "Status: Logged In";
        else
         txtStatus.Text = "Status: Not Logged In";
       }
      }  
      
  7. Our user control is complete. Now we can add an instance of the user control on our main login page. Open Page.xaml and add a xmlns reference directive to the UserControl element:
                   xmlns:AthleteManager="clr-namespace:AthleteManager" 
            
  8. Add an instance of the user control to the page. You may find it easier to open Page.xaml in Expression Blend and use the Asset Library to add and position the user control on the page.
                <AthleteManager:ucLoginStatus Height="27" Width="204" Canvas.Left="178" Canvas.Top="124" x:Name="ucLoginStatus1"/>
    
          
  9. Add code to Page.xaml.cs to set the IsLoggedIn property of the user control when the user logs in.
      void svc_AuthenticateUserCompleted(object sender, AthleteManager.AthleteService.AuthenticateUserCompletedEventArgs e)
      {
       if (e.Result)
       {
        System.Windows.Browser.HtmlPage.Window.Alert("Login successful");
        
        // display the status in the login status control
        ucLoginStatus1.IsLoggedIn = true;
       }
       else
       {
        System.Windows.Browser.HtmlPage.Window.Alert("Login Failed");
    
        // display the status in the login status control
        ucLoginStatus1.IsLoggedIn = false;
       }
      }
  10. Hit F5 to run the project and test to make sure the ucLoginStatus control displays and updates properly.

Exercise: Create a Blinking Custom Control

Duration: 30 to 45 minutes.

In this exercise, you will create a Custom Control which will give a "Blink" effect to text.

  1. Add a new class library project to the solution by right-clicking the AthleteManager solution in Solution Explorer and selecting Add/New Project and then "Silverlight Class Library." Name the project "MyCustomControls."
  2. Rename the Class1.cs file to BlinkBox.cs and change the class declaration so that it declares a class named BlinkBox, inherited from Control:
     public class BlinkBox:Control
     {
    
     }
                 
  3. Add a new Folder to the project called "Themes" by right-clicking the Project and selecting Add/New Folder.
  4. Inside the Themes folder, add a new file named "generic.xaml" with the following content, which defines the default UI and stylable content for the control:
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:MyCustomControls">
        <Style TargetType="local:BlinkBox">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:BlinkBox">
                        <Grid>
                            <TextBlock x:Name="txtContent" FontFamily="{TemplateBinding FontFamily}" 
    
    FontSize="{TemplateBinding FontSize}"
                                Foreground="{TemplateBinding Foreground}" 
    
    FontWeight="{TemplateBinding FontWeight}" 
                                FontStretch="{TemplateBinding FontStretch}" 
    
    FontStyle="{TemplateBinding FontStyle}"
                          />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    
  5. Select generic.xaml in the solution and set its Build Action to Resource in the Properties window.
  6. Select generic.xaml in the solution and set its Build Action to Resource in the Properties window.
  7. We'll use an empty StoryBoard as a Timer to create a "blink" effect on a TextBlock. Inside BlinkBox.cs, add code to define a StoryBoard, a boolean to track the flashing state, and a TextBlock variable to reference our TextBlock in generic.xaml. In the Loaded event for our custom control, we will start the StoryBoard timer to begin the flashing effect.
      Storyboard sbFlash = new Storyboard();
      bool isFlashing = false;
      TextBlock txtContent;
    
      public BlinkBox()
      {
       // DefaultStyleKey defines type used when defining style keys:
       DefaultStyleKey = typeof(BlinkBox);
    
       sbFlash.Duration = TimeSpan.FromSeconds(1);
       sbFlash.Completed += new EventHandler(sbFlash_Completed);
    
       this.Loaded += new RoutedEventHandler(BlinkBox_Loaded);
      }
      
      void BlinkBox_Loaded(object sender, RoutedEventArgs e)
      {
       sbFlash.Begin();
      }
      
  8. Add code to override the OnApplyTemplate method of our control so that we can get a reference to the TextBlock inside generic.xaml. Also add a method called HandleTextChanged to change the txtContent to a Dependency Property (to be defined in the next step) called "Text":
      public override void OnApplyTemplate()
      {
       // we need to manually get a reference to the content TextBlock
       // inside the style template
       txtContent = this.GetTemplateChild("txtContent") as TextBlock;
    
       HandleTextChanged();
    
       base.OnApplyTemplate();
      }            
      
      public void HandleTextChanged()
      {
       // set the text property
       if (txtContent != null)
        txtContent.Text = Text;
      }
                
  9. Add a Dependency Property so that users of the BlinkBox control can bind to and modify it's Text property. Note that we need to handle the PropertyChangedCallback event so that we can update the UI with any new Text property.
      public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(BlinkBox),
        new PropertyMetadata("", new PropertyChangedCallback((obj, args) =>
        {
         BlinkBox source = (BlinkBox)obj;
         source.HandleTextChanged();
        })));
    
      public string Text
      {
       get
       {
        return GetValue(TextProperty) as string;
       }
       set
       {
        SetValue(TextProperty, value);
       }
      }            
                
  10. Add a handler for the Storyboard completion event, which will create the blinking effect by changing the Opacity of the TextBlock:
                void sbFlash_Completed(object sender, EventArgs e)
      {
       if (isFlashing)
       {
        isFlashing = false;
        txtContent.Opacity = 0;
       }
       else
       {
        isFlashing = true;
        txtContent.Opacity = 1.0;
       }
       sbFlash.Begin();
      }
                
  11. Our Custom Control is now complete! Next we will add an instance of the custom control inside our Log In button, so that the Log In text blinks. Back in the main AthleteManager project, open Page.xaml and add another xmlns reference inside the UserControl element at the top of the page:
                    xmlns:MyCustomControls="clr-namespace:MyCustomControls;assembly=MyCustomControls"            
                
  12. We can now add an instance of the Blink control inside the button. Locate the btnLogin control in the XAML and remove its Content property, then add an instance of BlinkBox inside the Button's content:
                <Button Height="30" Width="169.098" Canvas.Left="406.902" Canvas.Top="71.074" x:Name="btnLogin">
                    <MyCustomControls:BlinkBox Text="Log in" />
                </Button>
                
                
  13. Hit F5 to test the project. The "Log In" text inside the login button should blink.
  14. Something to consider: What if we wanted to expose a "TimerInterval" property so that developers could modify the blink speed of our control? What steps would we take to implement that functionality?

Silverlight Controls Conclusion

In this lesson of the Silverlight tutorial, you

  • Learned about the controls available from Microsoft for Silverlight.
  • Applied skins to controls.
  • Modified the behavior and presentation of controls using data templates.
  • Implemented both a User Control and a Custom Control
To continue to learn Silverlight go to the top of this page and click on the next lesson in this Silverlight Tutorial's Table of Contents.
Last updated on 2009-05-19

Use of http://www.learn-silverlight-tutorial.com (Website) implies agreement to the following:

Copyright Information

All pages and graphics on Website are the property of Webucator, Inc. unless otherwise specified.

None of the content on Website may be redistributed or reproduced in any way, shape, or form without written permission from Webucator, Inc.

No Printing or saving of pages or content on Website

This content may not be printed or saved. It is for online use only.


Linking to Website

You may link to any of the pages on Website; however, you may not include the content in a frame or iframe without written permission from Webucator, Inc.


Warranties

Website is provided without warranty of any kind. There are no guarantees that use of the site will not be subject to interruptions. All direct or indirect risk related to use of the site is borne entirely by the user. All code and explanations provided on this site are provided without warranties to correctness, performance, fitness, merchantability, and/or any other warranty (whether expressed or implied).


For individual private use only

You agree not to use this online manual to deliver or receive training. If you are delivering or attending a class that is making use of this online manual, you are in violation of our terms of service. Please report any abuse to courseware@webucator.com. If you would like to deliver or receive training using this manual, please fill out the form at http://www.webucator.com/Contact.cfm