Mobile Corner

Customize the Windows Phone ToggleButton

Nick Randolph pulls apart the Windows Phone ToggleButton to help you adapt it to the look of your application.

One of the most important aspects of developing a Windows Phone application is understanding and taking advantage of the ability to restyle existing controls. For most applications you'll want to stick with the default style for most controls, as this will help you take advantage of the built-in Windows Phone style. It's usually sufficient to simply replace the content or define item templates in the case of a list. However, there are times when it's necessary to pull apart a control in order to restyle it. Windows Phone makes it easy to restyle a control without losing the basic functionality of the control.

In this article I'll start with the ToggleButton control that comes with the Windows Phone SDK. Figure 1 illustrates the main two states of a ToggleButton that have been dragged from the Assets window in Expression Blend onto the design surface.

Figure 1. ToggleButton states.

In this scenario I'm going to modify the ToggleButton to display a star in two different colors depending on whether it's in the checked (blue) or unchecked (green) state. Figure 2 illustrates the desired output.

Figure 2. Custom ToggleButton states.

The first step in this process is to open Expression Blend, create a new Windows Phone project and add an instance of the ToggleButton to the MainPage. The ToggleButton starts off using the implicit style that comes as part of the platform (as per Figure 1), in which it's possible to add content. For the star I'll use one of the application bar icons that ships with the SDK, which can be found at C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Icons\Dark\favs.png (you'll need to add this icon to your project and set the Build Action to Content). The following XAML adds this icon as content to the ToggleButton:

<ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top">
  <Image Source="/favs.png" Stretch="Fill" Height="76" Width="76"/>
</ToggleButton>
This has brought us one step closer to our goal of having different-colored stars. However, if you run your application at this point, you'll notice that when the ToggleButton is in the checked state the background changes color but the star doesn't. In order to change the color of the star, we need to modify the Template for the ToggleButton. To do this, right-click on the ToggleButton in Expression Blend, select Edit Template and then Edit a Copy. Give the new template a name, "ContentToggleButtonStyle," and click OK. This will take you into editting mode for the newly created template.

You'll see that the template for the ToggleButton is made up of two distinct parts that determine the layout for when it's enabled and disabled. The first thing I'll do is remove the white box that's part of the default style. Rather than modifying the structure, I'm simply going to remove the BorderBrush, BorderThickness and Margin attributes on both the EnabledBackground and DisabledBackground elements.

Both the EnabledBackground and DisabledBackground have a single ContentControl as their only child. The Image that I added as the Content of the ToggleButton is displayed by these ContentControls. In order to dynamically change the color of the star (without having to specify stars of different colors), I'm going to use the star image as an OpacityMask on a simple Border control. I'll start by replacing both ContentControls with Borders where the OpacityMask has been defined:

<Grid x:Name="EnabledBackground" Background="{TemplateBinding Background}" >
  <Border x:Name="EnabledContent" Background="{TemplateBinding Foreground}" 
    OpacityMask="{TemplateBinding Content}" Height="100" Width="100" />
  <Border x:Name="EnabledCheckedContent" Background="{TemplateBinding BorderBrush}" 
    Opacity="0" OpacityMask="{TemplateBinding Content}" Height="100" Width="100" />
</Grid>
<Border x:Name="DisabledBackground" Background="Transparent" IsHitTestVisible="False" 
  Visibility="Collapsed" Margin="0,-3,0,3">
  <Border x:Name="DisabledContent" Background="{StaticResource PhoneDisabledBrush}" 
    OpacityMask="{TemplateBinding Content}" Height="100" Width="100" />
</Border>

In doing this, you'll notice that the ToggleButton stops rendering the star. This is because it's attempting to use an Image control (which is the current Content of the ToggleButton) for the OpacityMark. This doesn't work, so you need to replace the Image with an ImageBrush, as the following XAML indicates:

<ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top" 
  Style="{StaticResource ContentToggleButtonStyle}">
  <ImageBrush ImageSource="/favs.png" Stretch="UniformToFill"/>
</ToggleButton>

You should now see the star appearing, but if you switch between the visual states while in editing mode for the template for the ToggleButton, you'll notice that Expression Blend displays error messages for certain states. This is because the visual states haven't been updated in line with the changes to the layout of the template. Modify the VisualStateGroups element so it appears like the code in Listing 1.

Listing 1. Modifying the VisualStateGroups element.
<VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Normal"/>
    <VisualState x:Name="Disabled">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" 
                                       Storyboard.TargetName="EnabledBackground">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Collapsed</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" 
                                       Storyboard.TargetName="DisabledBackground">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </VisualState>
  </VisualStateGroup>
  <VisualStateGroup x:Name="CheckStates">
    <VisualState x:Name="Unchecked"/>
    <VisualState x:Name="Checked">
      <Storyboard>
        <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" 
                                             Storyboard.TargetName="EnabledContent" 
                                             d:IsOptimized="True"/>
        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" 
                                             Storyboard.TargetName="EnabledCheckedContent" 
                                             d:IsOptimized="True"/>
      </Storyboard>
    </VisualState>
  </VisualStateGroup>
  <VisualStateGroup x:Name="FocusStates"/>
</VisualStateManager.VisualStateGroups>

If you look at the new structure, you'll see there are actually two Borders for the enabled state that represent when the ToggleButton is checked and unchecked. These bind to the Foreground and BorderBrush of the ToggleButton control, respectively, allowing you to control the star color by setting the Foreground (unchecked) and BorderBrush (checked) of the ToggleButton itself.

Now, this might seem like a lot of work to go through to simply specify a different-colored star for the different checked state of the ToggleButton. However, what's nice about this implementation is how easily you can reuse this style on a different ToggleButton using a different image and different colors. For example, the following XAML illustrates two instances of the ToggleButton that use different images and different color combinations:

<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  <ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top" 
    Style="{StaticResource ContentToggleButtonStyle}" 
    Foreground="Red" BorderBrush="#FF0CFF00">
    <ImageBrush ImageSource="/favs.png" Stretch="UniformToFill"/>
  </ToggleButton>
  <ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top" 
    Style="{StaticResource ContentToggleButtonStyle}" 
    Foreground="#FFD100FF" BorderBrush="#FF00FFF3">
    <ImageBrush ImageSource="/feature.camera.png" Stretch="UniformToFill"/>
  </ToggleButton>
</StackPanel>

In this article you've seen how to get started modifying a template for one of the built-in controls that ships with the Windows Phone SDK. This is only the tip of the iceberg in terms of what you can do by modifying templates and styles in order to adapt controls to match the style of your application.

 

About the Author

Nick Randolph runs Built to Roam, a consulting company that specializes in training, mentoring and assisting other companies build mobile applications. With a heritage in rich client applications for both the desktop and a variety of mobile platforms, Nick currently presents, writes and educates on the Windows Phone platform.

comments powered by Disqus

Featured

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube