Modifying existing Silverlight Controls

During development of a brand new Windows Phone 7 application, I ran into a dilemma. The application is a game in which the user needs to memorize a number of fields. After the playing board has been displayed for a limited amount of time, the user needs to find particular fields by clicking on them. The playing board looks like this:

Screen1 

The different squares that are part of the playing board follow the theme color that the user currently has selected on the phone. Since the user needs to be able to click on the different squares, it is necessary to deal with some form of hit testing. In my initial approach I decided to build the different squares as Silverlight Rectangles, all hosted in an individual row / column inside a Grid control. Each time the user hits one of those squares, something has to happen to its appearance. In my first attempt (when creating a quick and dirty prototype), I decided to subscribe to the MouseLeftButtonDown and MouseLeftButtonUp events since Rectangles do not implement Click events. By handling both button down and button up events and capturing the mouse in between a button down and a button up event sequence, I made sure to have both events acting on the same Rectangle. Even though this approach is feasible, it takes a lot of code, just to make sure that a proper click is recognized on a Rectangle. Since this game needs to react very fast on user input, I want to execute as little code as possible to recognize which Rectangle is currently selected by the user. Also, I want to write as little code as possible, and the whole mouse capturing in combination with some different actions that need to be done on the user ‘clicking’ a Rectangle got me into writing more and more code. Until of course I realized that it was time to do some thinking and to make use of the power of Silverlight, extending existing controls and ‘good old object oriented programming’. What if I could make use of a Button control? Silverlight Buttons do expose Click events, the Button takes care of low level MouseLeftButton handling and contain lots of other functionality. In fact, Buttons contain too much functionality for the different items of my playing board. If you take a look at the Button documentation, you can see the different button styles and all different visual states, including animations that are used to move from one visual state to another. For my particular need, this is way too much functionality. So what if I can limit the functionality of a button (to only display a colored square and to expose a Click event)?

PlayButton – A very simple derived and restyled Silverlight Button

I started by creating a new Windows Phone Class Library to an existing solution in Visual Studio 2010. This Class Library contains my PlayButton class, that simply derives from Button. Replacing the original Rectangle controls on my playing board by PlayButton controls gave the following result:

Screen2

 

Surely, the Rectangles are replaced by PlayButtons. Because PlayButton derives from Button without modifying anything, a PlayButton is simply a Button. This is the reason why a border is shown and why the theme color of the original Rectangles is lost. It also means that there are placeholders for Content and it is possible to act on Click events. However, each time a button is clicked it is going through a number of state transitions, potentially slowing down users that want to play this particular game. To overcome these issues, I created a brand new control template, including a default style to define and render my PlayButton. In order to work properly, the default style needs to be defined in a file called ‘generic.xaml’ that should be stored in a Folder called “Themes” inside the project that hosts the user control. In this particular case, my Visual Studio 2010 solution looks like this:

SolutionExplorer

 

Instead of creating a new user control, including a control template and a default style, I could also have taken an alternative approach, using Expression Blend to create and modify a copy of the existing Button Control style and store the new style as resource in my Windows Phone application or in the Windows Phone application page where the style will be used. This approach is a little bit easier. I did chose to create a new default style for this particular application because I might want to re-use the PlayButton for a few other applications as well. The style I am using for the PlayButton defines a BorderControl that takes the Background and the Opacity that are defined for Button controls. The Background defaults to a PhoneAccentBrush, allowing the PlayButton to be theme aware. Here is the complete XAML for the PlayButton (definied in generic.xaml):

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/client/2007&quot;
  2.                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  3.                     xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  4.                     xmlns:src="clr-namespace:ClickerControls"
  5.                     xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
  6.     <Style TargetType="src:PlayButton">
  7.         <Setter Property="Width"
  8.                 Value="100" />
  9.         <Setter Property="Height"
  10.                 Value="100" />
  11.         <Setter Property="Margin"
  12.                 Value="2" />
  13.         <Setter Property="Background"
  14.                 Value="{StaticResource PhoneAccentBrush}" />
  15.         <Setter Property="Opacity"
  16.                 Value="0.5" />
  17.         <Setter Property="Template">
  18.             <Setter.Value>
  19.                 <ControlTemplate TargetType="src:PlayButton">
  20.                     <Border x:Name="RootElement"
  21.                             Background="{TemplateBinding Background}"
  22.                             Opacity="{TemplateBinding Opacity}">
  23.                     </Border>
  24.                 </ControlTemplate>
  25.             </Setter.Value>
  26.         </Setter>
  27.     </Style>
  28. </ResourceDictionary>

As you can see in the XAML, both the style and the control template specify the control for which they are intended (being src:PlayButton). All that is left to do is setting the DefaultStyleKey to refer to the default style for the control.

  1. public class PlayButton : Button
  2. {
  3.     public PlayButton()
  4.     {
  5.         DefaultStyleKey = typeof(PlayButton);
  6.     }
  7. }

This is all there is to do to create a PlayButton which inherits Click events from a Button Control. The PlayButtons look identical to the original Rectangles, but they are simpler to use inside this particular application.

Screen1

 

Hopefully, this blog entry helps you making a decision on re-using existing Silverlight controls. You can give existing controls a completely new look and feel by applying new styles. Often you might be thinking about adding functionality to existing controls or adding behavior to existing controls. However, it is also completely valid to limit existing behavior on controls, just like this example shows. The PlayButton acts on Click events, but the PlayButton itself will not give visual feedback when it is clicked or when the PlayButton is disabled. So it is really up to you to get all the functionality you want. In my opinion, Silverlight is extremely powerful in allowing you to alter the appearance of existing controls or create new controls based on existing controls. I get more excited by the day that this Silverlight based programming model is one of the two different technologies that you can use to develop applications for Windows Phone 7.