WEBSITE

Silverlight : Controls - Replacing the Default UI of a Control

1/2/2013 6:35:42 PM

1. Problem

Every control has an out-of-the-box user interface. You want to replace this default UI with a custom one without having to write a new control.

.2. Solution

Design a custom control template to express the new UI for the control, and apply it to the control using the Template property or through a Style in your application's XAML.

3. How It Works

Every Silverlight control that renders itself visually at runtime needs its UI defined as a part of the control writing process. The preferred mode of defining this UI is by designing a self-contained block of XAML and associating it with the control so that it can be loaded and rendered by the control code. This block of XAML is what forms the default control template for that control.

3.1. Control Template Syntax

A control template always starts with the XAML element <ControlTemplate>. The TargetType attribute must supply the CLR type of the control to which the template can be applied. Here is a sample declaration:

<UserControl.Resources>
  <ControlTemplate x:Key="ctCustomRadioButton" TargetType="RadioButton">
  <!--Template Definition Here -->
  </ControlTemplate>
</UserControl.Resources>

Inside the <ControlTemplate> tag, you can have any XAML as long as it is renderable. The template is typically defined as a stand-alone resource in a resource dictionary, where the x:Key attribute specifies the unique key for the template by which it can be referenced when applied to the control. 

3.2. Setting the Template

The Control base class exposes a Template property that can be set on any control to replace its template, as shown here:

<RadioButton Template="{StaticResource ctCustomRadioButton}"/>

You can also use a style to apply a template to a control, like so:

<Style TargetType="RadioButton" x:Name="styleGelRadioButton">
  <Setter Property="Template" Value="{StaticResource ctCustomRadioButton}"/>
  <!--Other setters here -->
</Style>
<!--apply the Style and hence the template-->
<RadioButton Style="{StaticResource styleGelRadioButton}"/>

					  

In the previous examples, you define the control templates as stand-alone resources; then, you reference them in a style or apply them using the Template property. Note that control templates can also be defined inline without having to declare them as a separate resource. The following XAML code demonstrates this:

<!-- defined in place in a Style -->
<Style TargetType="RadioButton" x:Name="styleGelRadioButton">
  <Setter Property="Template">
      <Setter.Value>
          <ControlTemplate TargetType="RadioButton">
              <!-- rest of the template -->
          </ControlTemplate>
      </Setter.Value>
  </Setter>
  <!-- rest of the setters -->
</Style>

<!-- defined in place in a control declaration -->
<RadioButton>
  <RadioButton.Template>
      <ControlTemplate TargetType="RadioButton">
          <!-- rest of the template -->
      </ControlTemplate>
  </RadioButton.Template>
</RadioButton>

3.3. Using Expression Blend to Design a Template

Expression Blend offers excellent support for designing Silverlight user interfaces, including designing custom templates for controls. For a general introduction to Expression Blend usage and to UI design. This recipe discusses Expression Blend 3 features that apply to control template design.

Once you have the control added to your scene in the Expression Blend designer window, you can right-click the control to bring up its context menu, as shown in Figure 1.

Figure 1. Control context menu in Expression Blend

You have the option of either creating an empty control template or having Expression Blend generate a copy of the default template. If the modifications you want to make are minor, it is often helpful to start with a copy. A copy also gives you a good look into the intentions of the original designers of the control. Note that when you choose to edit a copy, Expression Blend actually creates a style with the control template defined within that style using a setter for the Template property.

Once you specify a key for the new control template for the RadioButton as shown in Figure 2 (or the encapsulating style, in the event you decide to edit a copy), Expression Blend switches the designer over to the control template for the RadioButton. If you chose to create an empty template, Expression Blend creates a mostly empty visual tree for the control contained in a Grid for layout. If you chose to edit a copy, Expression Blend creates a style that contains a copy of the entire visual tree as supplied by the default template, which you can then modify. Figure 3 shows the differences.

Figure 2. Naming a template

Figure3. Empty control template versus editing a copy

From here on, designing the template is similar to designing any other XAML-based UI in Expression Blend. Some additional features are discussed next.

3.4. Template Bindings

When you are designing a control template, you have the option of setting values for the properties of the various elements that make up that template. In many cases, it may make sense to derive those values from the corresponding property settings on the control at the point of its use in an application. For example, you may want the Background property of an element inside the control template of a control to assume whatever value is set on the Background property on the control itself when it is being used. However, when you are designing the control template, you have no way of knowing what those values might be. Therefore, you need a mechanism to indicate that a certain property value on an element in the template will be bound to a matching property value of the control at the point of use. The TemplateBinding construct allows you to do just that:

<ControlTemplate x:Key="ctGelRadioButton" TargetType="RadioButton">
  <Grid MaxHeight="{TemplateBinding MaxHeight}"
        MaxWidth="{TemplateBinding MaxWidth}"
        Background="{TemplateBinding Background}">
      <Ellipse Margin="0,0,0,0" x:Name="OuterRing"
      Stroke="{TemplateBinding Foreground}" StrokeThickness="2">
      </Ellipse>
  </Grid>
</ControlTemplate>

For the RadioButton control template shown here, you have the MaxHeight, MaxWidth, and Background properties of the top-level Grid and the Foreground property of the Ellipse template bound. These template bindings will cause whatever values are supplied to these properties in a RadioButton declaration to be applied to these elements in the template. Template bindings are useful when you need the control consumer to be able to affect properties of the parts of the control template without having direct access to the parts themselves. However, it is not mandatory that template bindings be used in every control template definition.

If you are designing the template in Expression Blend 3, the context menu for each property (accessible by clicking the little rectangle on the right of the property editor) offers the choices of parent properties that you can bind to (see Figure 4).

Figure 4. Binding a property within a template using Expression Blend 3

3.5. Content Model and Presenter Controls

Controls often present content to the user, as well as interactivity and event functionality. For example, in Figure 5, the Option 1 is the content being displayed by the radio button. The part of the control design that specifies how it displays content is called the content model of the control.

Figure 5. Radio button with simple content

To better understand this, let's consider the System.Windows.Controls.ContentControl type. The ContentControl has a dependency property called Content that can be set or bound to any content, which the ContentControl instance then displays. In case there is no built-in knowledge of how to display this content, you can also associate a data template through the ContentTemplate property to facilitate the display of the content. More than being useful in and of itself, the ContentControl serves as a base class for many other controls in Silverlight, such as Label, Button, or the RadioButton shown earlier.

The following code shows the XAML declaration for the RadioButton in Figure 5:

<RadioButton Content="Option 1" />

Figure 6 shows a radio button with slightly more complex content, including a text caption and an image displayed with the help of a data template.

Figure 6. Radio button with complex content

This XAML code shows the RadioButton declaration:

<RadioButton Content="{Binding}" x:Name="rbtn">
  <RadioButton.ContentTemplate>
      <DataTemplate>
          <Grid>
              <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="Auto"/>
                  <ColumnDefinition Width="Auto"/>
              </Grid.ColumnDefinitions>
              <TextBlock Text="{Binding Caption}" Grid.Column="0"
TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center"/>
              <Image Source="{Binding Icon}" Grid.Column="1" Stretch="Fill"
idth="24" Height="24" Margin="3,0,0,0"/>
          </Grid>
      </DataTemplate>
  </RadioButton.ContentTemplate>
</RadioButton>

					  

The content for the RadioButton can be set by setting its DataContext property to some instance of a CLR type that exposes two properties: Caption and Icon.

When you modify the control template for a control, you should be aware of the intended content model for that control. To be fair to the control author's intentions, try to retain the same content model in your custom template. To facilitate this, the Silverlight control framework provides a specific category of controls called presenters. A presenter's purpose is to create a placeholder for content inside a control template. Through appropriate template bindings, content gets passed on to the presenter, which then displays the content in the rest of the visual tree of the template. You can also associate a data template (again, preferably through a template binding), which is then used by the presenter to display the content.

Several types of content models and corresponding presenters are supplied in the framework. For this sample, you need to understand the most fundamental of them all: the ContentPresenter control.

This XAML shows a ContentPresenter in action in a template for a RadioButton:

<ControlTemplate x:Key="ctCustomRadioButton"
                   TargetType="RadioButton">
  <Grid>
   <!-- rest of the template -->
    <ContentPresenter HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Grid.Column="1" Margin="2,0,0,2"
          Content="{TemplateBinding Content}"
          ContentTemplate="{TemplateBinding ContentTemplate}"/>
  </Grid>

</ControlTemplate>

Notice the template bindings for the Content and the ContentTemplate properties of the ContentPresenter, which allow the values set for these properties on any instance of the RadioButton to be passed into the ContentPresenter for display. As you saw in Figures 5-6 and 5-7, the content (a string in the first case and some XAML with a specific data binding for the image in the second) is passed in using this mechanism. If those template bindings were absent or if you did not have a ContentPresenter, setting the Content or the ContentTemplate property on the RadioButton would have no effect, since there would be no placeholder inside the control's template to display that content.

3.6. Visual State Management

Controls often change their visual state as users interact with them. A check mark that appears in a Checkbox or a Button when it is clicked is an example of a visual state change. The Silverlight control framework includes a Visual State Manager (VSM) component that can be used to manage these state transitions.

The various possible visual states for a control are defined by the control author and further logically grouped into state groups. Each state managed by the VSM is implemented as a StoryBoard that can contain one or more animations that define the visual representation of moving from one state to another. When designing a control template using Expression Blend, you can see the various state groups and the specific states in the States editor, as shown in Figure 7.

Figure 7. The control template's States editor in Expression Blend

When you select a specific state, Expression Blend transitions into a storyboard recording mode for that state (see Figure 8).

Figure 8. Recording a state change

Recording a state change works just like recording a regular storyboard in Expression Blend, including the use of the storyboard time line editor to define a timeline for a specific keyframe animation in the state storyboard. 

In addition to defining each individual state as a storyboard, you can also optionally define the time duration of the transition from one state to another. Clicking the state transition icon displays all the possible state transitions involving that state. Figure 9 shows the possible transitions to and from the MouseOver state for a control template, with * indicating any state.

Figure 9. State transitions for the MouseOver state

In Figure 9, the transition duration from another state to the MouseOver state has been defined as a quarter of a second. The following XAML shows a sample set of states and some of the possible transitions defined:

<vsm:VisualStateManager.VisualStateGroups>
  <vsm:VisualStateGroup x:Name="CommonStates">
    <vsm:VisualStateGroup.Transitions>
      <vsm:VisualTransition  GeneratedDuration="00:00:00.2500000" To="MouseOver"/>
      <vsm:VisualTransition GeneratedDuration="00:00:00.2500000" From="MouseOver"/>
    </vsm:VisualStateGroup.Transitions>
    <vsm:VisualState x:Name="Disabled"/>
    <vsm:VisualState x:Name="Normal">
      <Storyboard/>
    </vsm:VisualState>
    <vsm:VisualState x:Name="MouseOver">
      <Storyboard>
        <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
          Duration="00:00:00.0010000"
          Storyboard.TargetName="OuterRing"
          Storyboard.TargetProperty=
              "(Shape.Stroke).(SolidColorBrush.Color)">
          <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>
        </ColorAnimationUsingKeyFrames>
        <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
          Duration="00:00:00.0010000"
          Storyboard.TargetName="InnerCore"
          Storyboard.TargetProperty=
    "(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
          <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>
        </ColorAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Pressed"/>
  </vsm:VisualStateGroup>
  <vsm:VisualStateGroup x:Name="FocusStates">
    <vsm:VisualState x:Name="Unfocused">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames
          Storyboard.TargetName="FocusIndicator"
          Storyboard.TargetProperty="Visibility"
          Duration="0">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Collapsed</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Focused">

					  

<Storyboard>
        <ObjectAnimationUsingKeyFrames
          Storyboard.TargetName="FocusIndicator"
          Storyboard.TargetProperty="Visibility"
          Duration="0">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="ContentFocused">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames
          Storyboard.TargetName="FocusIndicator"
          Storyboard.TargetProperty="Visibility"
          Duration="0">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
  </vsm:VisualStateGroup>
  <vsm:VisualStateGroup x:Name="CheckStates">
    <vsm:VisualStateGroup.Transitions>
      <vsm:VisualTransition GeneratedDuration="00:00:00.2500000" To="Checked"/>
      <vsm:VisualTransition GeneratedDuration="00:00:00.2500000" From="Checked"/>
    </vsm:VisualStateGroup.Transitions>
    <vsm:VisualState x:Name="Unchecked">
      <Storyboard/>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Checked">
      <Storyboard>
        <ColorAnimationUsingKeyFrames
          BeginTime="00:00:00"
          Duration="00:00:00.0010000"
          Storyboard.TargetName="InnerCore"
          Storyboard.TargetProperty=
    "(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
          <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>

					  

</ColorAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Indeterminate"/>
  </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

Each visual state for the control is declared as a <vsm:VisualState> element, and each state has an associated storyboard, which can include one or more animations that all get executed by the runtime when that visual state is reached. These animations typically animate various properties of different parts of the control template to give the necessary visual cue indicating the state change. As an example, in the MouseOver state storyboard, you have two animations defined within the storyboard. The first one animates the Stroke property on an element named OuterRing to a different solid color. The second one animates the Fill property of another element named InnerCore to a different gradient. You can also have an empty storyboard if you do not want to define any particular visual change for the control upon reaching that state. The control's code determines when a specific visual state is reached.

You should also note the <vsm:VisualStateGroup> declarations that group visual states together. The VisualStateManager mandates that each state be contained in a group (even if that is the only state in it) and that each state be defined in exactly one group. You can also see <vsm:VisualTransition> elements declared inside a state group. Each defined visual transition is a way to specify a time duration over which a transition from one state to another in a group should happen. In the previous example, transition from any state to the MouseOver state or the reverse is specified to happen over a quarter of a second, as it is for the Checked state.

Note that you are not required to define an explicit storyboard for each state. For example, it is common to not define anything explicit for the Normal state, since the default visual representation of the control template can be considered its normal state. However, that does not mean that you can leave out the state definition completely. In the case of the Normal state, for example, the empty storyboard causes the RadioButton to revert to its default look when none of the other defined visual states are applicable; thus, the Normal state is reached. If you left out that state definition, the control would never revert to the default look once it transitions out of another state.

4. The Code

The code sample in this recipe replaces the default control template of a RadioButton with a custom template. Listing 1 shows the full XAML for the page.

Listing 1. Defining and applying a custom RadioButton control template
<UserControl x:Class="Recipe5_2.MainPage"
    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>
    <!-- The Custom Control Template targeting a RadioButton -->
    <ControlTemplate x:Key="ctCustomRadioButton"
                     TargetType="RadioButton">

<Grid Background="{TemplateBinding Background}"
                  MinHeight="{TemplateBinding MinHeight}"
                  MinWidth="{TemplateBinding MinWidth}"
                  MaxWidth="{TemplateBinding MaxWidth}"
                  MaxHeight="{TemplateBinding MaxHeight}">
        <vsm:VisualStateManager.VisualStateGroups>
          <vsm:VisualStateGroup x:Name="CommonStates">
            <vsm:VisualStateGroup.Transitions>
              <vsm:VisualTransition  GeneratedDuration="00:00:00.2500000"
 To="MouseOver"/>
              <vsm:VisualTransition GeneratedDuration="00:00:00.2500000"
 From="MouseOver"/>
            </vsm:VisualStateGroup.Transitions>
            <vsm:VisualState x:Name="Disabled"/>
            <vsm:VisualState x:Name="Normal">
              <Storyboard/>
            </vsm:VisualState>
            <vsm:VisualState x:Name="MouseOver">
              <Storyboard>
                <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                  Duration="00:00:00.0010000"
                  Storyboard.TargetName="OuterRing"
                  Storyboard.TargetProperty=
                      "(Shape.Stroke).(SolidColorBrush.Color)">
                  <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>
                </ColorAnimationUsingKeyFrames>
                <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                  Duration="00:00:00.0010000"
                  Storyboard.TargetName="InnerCore"
                  Storyboard.TargetProperty=
            "(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                  <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Pressed"/>
          </vsm:VisualStateGroup>
          <vsm:VisualStateGroup x:Name="FocusStates">
            <vsm:VisualState x:Name="Unfocused">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames
                  Storyboard.TargetName="FocusIndicator"
                  Storyboard.TargetProperty="Visibility"
                  Duration="0">
                  <DiscreteObjectKeyFrame KeyTime="0">

					  

<DiscreteObjectKeyFrame.Value>
                      <Visibility>Collapsed</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                  </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
              </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Focused">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames
                  Storyboard.TargetName="FocusIndicator"
                  Storyboard.TargetProperty="Visibility"
                  Duration="0">
                  <DiscreteObjectKeyFrame KeyTime="0">
                    <DiscreteObjectKeyFrame.Value>
                      <Visibility>Visible</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                  </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
              </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="ContentFocused">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames
                  Storyboard.TargetName="FocusIndicator"
                  Storyboard.TargetProperty="Visibility"
                  Duration="0">
                  <DiscreteObjectKeyFrame KeyTime="0">
                    <DiscreteObjectKeyFrame.Value>
                      <Visibility>Visible</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                  </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
              </Storyboard>
            </vsm:VisualState>
          </vsm:VisualStateGroup>
          <vsm:VisualStateGroup x:Name="CheckStates">
            <vsm:VisualStateGroup.Transitions>
              <vsm:VisualTransition GeneratedDuration="00:00:00.2500000"
 To="Checked"/>
              <vsm:VisualTransition GeneratedDuration="00:00:00.2500000"
 From="Checked"/>
            </vsm:VisualStateGroup.Transitions>
            <vsm:VisualState x:Name="Unchecked">
              <Storyboard/>

					  

</vsm:VisualState>
            <vsm:VisualState x:Name="Checked">
              <Storyboard>
                <ColorAnimationUsingKeyFrames
                  BeginTime="00:00:00"
                  Duration="00:00:00.0010000"
                  Storyboard.TargetName="InnerCore"
                  Storyboard.TargetProperty=
            "(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                  <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF144EEA"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Indeterminate"/>
          </vsm:VisualStateGroup>
        </vsm:VisualStateManager.VisualStateGroups>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="0.20*"/>
          <ColumnDefinition Width="0.80*"/>
        </Grid.ColumnDefinitions>
        <Ellipse Margin="0,0,0,0" x:Name="OuterRing"
                 Stroke="#00000000" StrokeThickness="2">
          <Ellipse.Fill>
            <LinearGradientBrush
              EndPoint="1.13300001621246,1.13999998569489"
              StartPoint="−0.0640000030398369,−0.0560000017285347">
              <GradientStop Color="#FF000000"/>
              <GradientStop Color="#FFADADAD" Offset="1"/>
            </LinearGradientBrush>
          </Ellipse.Fill>
        </Ellipse>
        <Grid Margin="0,0,0,0">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.2*"/>
            <ColumnDefinition Width="0.6*"/>
            <ColumnDefinition Width="0.2*"/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="0.2*"/>
            <RowDefinition Height="0.6*"/>
            <RowDefinition Height="0.2*"/>
          </Grid.RowDefinitions>
          <Ellipse x:Name="InnerRing"
                   Fill="#FF000000"
                   Grid.Column="1" Grid.Row="1"/>

					  

<Ellipse Grid.Row="1" Grid.Column="1"
                   x:Name="InnerCore" Margin="0,0,0,0">
            <Ellipse.Fill>
              <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFFFFFFF"/>
                <GradientStop Color="#FF000000" Offset="1"/>
              </LinearGradientBrush>
            </Ellipse.Fill>
          </Ellipse>
        </Grid>
        <ContentPresenter HorizontalAlignment="Center"
                          VerticalAlignment="Center"
                          Grid.Column="1" Margin="2,0,0,2"
            Content="{TemplateBinding Content}"
            ContentTemplate="{TemplateBinding ContentTemplate}"/>
        <Rectangle Stroke="Black" x:Name="FocusIndicator" Grid.Column="1"
                   StrokeThickness="0.5" Height="1"
                   HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
                   Margin="2,0,0,0" />
      </Grid>
    </ControlTemplate>

    <!-- A style targeting the RadioButton referencing the control template -->
    <Style TargetType="RadioButton" x:Name="styleGelRadioButton">
      <Setter Property="Template" Value="{StaticResource ctCustomRadioButton}"/>
      <Setter Property="Height" Value="20" />
      <Setter Property="Width" Value="100" />
      <Setter Property="Background" Value="Transparent" />
    </Style>
  </UserControl.Resources>

  <Grid x:Name="LayoutRoot" Background="White" Margin="20,20,20,20">
    <Grid.RowDefinitions>
      <RowDefinition Height="0.5*"/>
      <RowDefinition Height="0.5*"/>
    </Grid.RowDefinitions>
    <!-- A RadioButton with default look & feel -->
    <RadioButton  HorizontalAlignment="Left" VerticalAlignment="Top"
                  Content="RadioButton" GroupName="Test" Grid.Row="0"/>
    <!-- A RadioButton with the style (and hence the custom template) applied -->
    <RadioButton  HorizontalAlignment="Left" VerticalAlignment="Top"
                  Content="RadioButton"
                  Style="{StaticResource styleGelRadioButton}"
                  GroupName="Test" Grid.Row="1"/>

					  

</Grid>
</UserControl>

In Listing 1, the RadioButton control template, named ctCustomRadioButton, is primarily made up of three Ellipses (two Ellipses named InnerRing and InnerCore, situated in a Grid within the outer Ellipse named OuterRing). There is also a ContentPresenter to display any bound content, as well as a Rectangle (with Height set to 1 so that it appears as an underscore below the content) serving as a focus indicator, which has its Visibility initially set to Collapsed.

Figure 10 shows the Normal state comparisons between the custom template RadioButton and the default template.

Figure 10. RadioButton Normal state with (left) and without (right) the custom template

The MouseOver state is defined using a storyboard that changes the Stroke color of OuterRing and the Fill color of InnerRing. The result in comparison to the default RadioButton template is shown in Figure 11.

Figure 11. RadioButton MouseOver state with (left) and without (right) the custom template

The Focused and ContentFocused state storyboards make the FocusIndicator rectangle visible, while the Unfocused state storyboard hides it. The Checked state storyboard modifies the Fill color of the ellipse InnerCore. Figure 12 shows the Checked state of the RadioButton with focus on it.

Figure 12. RadioButton Checked and Focused states with (left) and without (right) the custom template

You also declare a style named styleGelRadioButton. You reference ctCustomRadioButton using a setter for the Template property and set a few other defaults for some of the other properties in the control template. And last, for the page's UI, you declare two RadioButtons—one using just the default look and feel defined by the framework and the other with the style styleGelRadioButton applied to it so that the custom template gets applied to it as well—to help you compare them visually.

Another important thing to note is the presence of specific elements in the control template definition with predetermined names. When the original control author designs the control, there may be dependencies in the control's code or in the definition of the default state change storyboards that require specific names for different parts of the control template. If you decide to leave those elements out of your new control template or name them differently, certain parts of the control's feature set or its visual representation may be rendered unavailable.

An example in Listing 1 is the Rectangle named FocusIndicator. The RadioButton's default implementation includes state definitions for the Focused, Unfocused, and ContentFocused states that toggles the visibility of this Rectangle based on whether focus is on the control. If you leave out or rename this Rectangle in your new template, you need to reauthor the state storyboards appropriately for the focus visual cue to function.

Control authors are advised to write controls defensively so that a name dependency does not crash an application; instead, the control just silently shuts down the dependent feature. However, depending on the importance of the named element in the control's overall functionality, leaving or renaming certain elements may render the control useless. We suggest that you look at the definition of the default control template in the documentation on the MSDN website. This knowledge can help you make an informed decision about any modifications.

However, if the dependency is in XAML through some state storyboard reference, you have the ability to modify the storyboard if you modify the element.

Other  
 
Video
Top 10
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
The latest Audi TT : New angles for TT
Era of million-dollar luxury cars
Game Review : Hearthstone - Blackrock Mountain
Game Review : Battlefield Hardline
Google Chromecast
Keyboards for Apple iPad Air 2 (part 3) - Logitech Ultrathin Keyboard Cover for iPad Air 2
Keyboards for Apple iPad Air 2 (part 2) - Zagg Slim Book for iPad Air 2
Keyboards for Apple iPad Air 2 (part 1) - Belkin Qode Ultimate Pro Keyboard Case for iPad Air 2
Michael Kors Designs Stylish Tech Products for Women
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone