How Styles and ControlTemplates Work: The Control Contract

Monday, 26 May 2008 22:25 by snyhol

TECHNOLOGY USED: SILVERLIGHT 2, BETA 1

I recently posted some simple examples that demonstrate the power of Styles and ControlTemplates to skin your Silverlight applications.  Now let's talk about how it works.  Controls can be built to separate their visual appearance (i.e., the rectangular shape) from their behavior (i.e., firing a Click event).  This separation is facilitated with a "control contract" that implements the "parts control model."  This approach separates the appearance of the control into TemplateParts that can be replaced via ControlTemplates.  The contract specifies the following three items:

  • Public properties that can be set using Styles or inline property assignments
    • Defined as public DependencyProperty
  • UIElement objects that define the appearance
    • Defined with TemplatePart attributes
  • Storyboard objects that define how the control changes appearance in response to events
    • Defined with TemplatePart attributes

The Styling and Templating Overview provides this simple example of a control contract:

        [TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement))]
        [
TemplatePart(Name = "FocusVisualElement", Type = typeof(FrameworkElement))]

        [
TemplatePart(Name = "Normal State", Type = typeof(Storyboard))]
        [
TemplatePart(Name = "MouseOver State", Type = typeof(Storyboard))]
        [
TemplatePart(Name = "Pressed State", Type = typeof(Storyboard))]

       
public class MyButton : Control {
           
public static readonly DependencyProperty TextProperty;
           
public static readonly DependencyProperty ForegroundProperty;
           
public static readonly DependencyProperty FontSizeProperty;

           
public string Text { get; set; }
           
public Brush Foreground { get; set; }
           
public double FontSize { get; set; }

        }

Learning about the control contract, or parts control model, will provide you with a deeper understanding of Styles and ControlTemplates.  New controls should be written with a control contract to allow others to skin them. 

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   Software Dev
Actions:   E-mail | Permalink | Trackback | Comments (0) | Comment RSSRSS comment feed

Solar Shooter: A Gas Guzzler's Nightmare

Friday, 23 May 2008 16:54 by snyhol

Frustrated by the high gas prices at the pump? Blow off some steam playing “Solar Shooter: A Gas Guzzler’s Nightmare.” In this shoot’em up arcade game, it’s you vs. the gas guzzlers. Use your solar powered, electricity shooting hover car to face off against the single occupant commuter, the angry guy in the SUV, and even the dreaded gas station pump. Gotta zap them before they soak you. 

      Solar-Shooter-Big

Solar Shooter is the first game posted to www.SL42.com.  The first version of the game was submitted to the "RIA Run" competition hosted by Internet.com and Microsoft.com.  It was selected as a finalist!!!  Support my entry and play the RIA Run Contest version between May 16, 2008 and June 5, 2008.

Solar Shooter was built with Silverlight 2.  I previously posted a complete listing of Silverlight features used in the game. 

Download the source code using this link: SolarCarBeta1.zip

Please post comments about Solar Shooter here. The next version of Solar Shooter is scheduled to include:

  • Bosses
  • Special weapons
  • Brakes for the car
  • Sound effects for ammo and explosions
  • Level unlock codes
  • Global scoreboard

I look forward to posting the next version.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:   ,
Categories:   SL42 games | Software Dev
Actions:   E-mail | Permalink | Trackback | Comments (2) | Comment RSSRSS comment feed

Silverlight Skinning with ControlTemplates

Thursday, 22 May 2008 13:52 by snyhol

TECHNOLOGY USED: SILVERLIGHT 2, BETA 1

In a recent post, I showed how Styles can be used to change one property of the existing appearance of a control, similar to CSS.  For example, the Button has a Foreground property that can be used to change the color of the text it contains.  You can use a Style object to set this foreground color for several Button controls.  Styles have limits.  You cannot use a Style to change the shape of a Button.  A Style cannot make a rectangular-shaped button look round. 

That's where the ControlTemplate is useful.  It was designed specifically for changing the shape of a control.  It can be used to change that rectangular-shaped button into a round one, as Jesse Liberty demonstrated in his Styles and Templates tutorial.  Another excellent post that clearly explains ControlTemplates is Creating a Custom Skin by Matt Berseth.

Some things to notice about Skinning with a ControlTemplate are:

  • ControlTemplates are written inside a Style definition, using Property="Template".
  • You can mix "normal" Styles and ControlTemplates in the same Style definition.  The "normal" Styles become the default Style for your skin.
  • The Setter's value must be set to a ControlTemplate.
  • The root visual element in the ControlTemplate must be named x:Name="RootElement"
  • You can use the property values assigned by the consumer of the template, using the {TemplateBinding PropertyName} syntax.
  • Storyboards are used to change the appearance of the control when the visual state changes, for example during the MouseOver event. 
  • The normal state is the default and starting state of the control.  I did not need to provide any animation for this state.
  • You can use DoubleAnimation, ColorAnimation, and ObjectAnimationUsingKeyFrames.
  • You can animate attached properties, using syntax like (Rectangle.Stroke).(SolidColorBrush.Color).
  • You cannot use TemplateBinding values in animations.
  • You cannot have two objects in the ControlTemplate with the same x:Name
  • Objects with special names defined in the control contract will receive special functionality from the base control's behavior.  For example, a HyperlinkButton's FocusVisualElement will be invisible unless the control has focus... at which time, the FocusVisualElement becomes visible. 

 

An Example Template Skin for HyperlinkButton

The typical example is making a button round.  To make my example a little more interesting, I'll do something different: adding a border to a HyperlinkButton, taking care to provide visual clues for all states defined in the HyperlinkButton's control contract: having focus, MouseOver, Pressed, and Disabled.  This skin allows for resizing and uses the values assigned by the consumer of this ControlTemplate. 

    <Application.Resources>
        <Style x:Key="HyperlinkWithBorder" TargetType="HyperlinkButton">
            <!-- SET DEFAULT STYLE -->
            <Setter Property="IsEnabled" Value="true" />
            <Setter Property="IsTabStop" Value="true" />
            <Setter Property="Foreground" Value="#FF417DA5" />
            <Setter Property="Cursor" Value="Hand" />
            <Setter Property="TextAlignment" Value="Left" />
            <Setter Property="HorizontalContentAlignment" Value="Left" />
            <Setter Property="VerticalContentAlignment" Value="Top" />
            <Setter Property="TextWrapping" Value="NoWrap" />
            <Setter Property="FontSize" Value="11" />
            <!-- Cannot currently parse TextDecorationCollection type in XAML so it's being set in code -->
            <!-- <Setter Property="TextDecorations" Value="Underline" /> -->
            <!-- Cannot currently parse FontFamily type in XAML so it's being set in code -->
            <!-- <Setter Property="FontFamily" Value="Trebuchet MS" /> -->
            <!-- Cannot currently parse FontWeight type in XAML so it's being set in code -->
            <!-- <Setter Property="FontWeight" Value="Bold" /> -->
           
           
<!-- DEFINE CONTROL TEMPLATE -->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="HyperlinkButton">
                        <Grid x:Name="RootElement"
                      
Cursor="{TemplateBinding Cursor}">
                            <Grid.Resources>
                               
                               
<!-- Visual states of the template -->
                                <Storyboard x:Key="Normal State" />
                               
                               
<Storyboard x:Key="MouseOver State" >
                                    <DoubleAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="FaderRect" 
                                  
Storyboard.TargetProperty="Opacity"
                                  
To=".1" />
                                    <DoubleAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="VisualPopRect" 
                                  
Storyboard.TargetProperty="Opacity"
                                  
To="1" />
                                </Storyboard>
                               
                               
<Storyboard x:Key="Pressed State" >
                                    <DoubleAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="FaderRect"
                                   Storyboard.TargetProperty="Opacity"
                                  
To=".3" />
                                    <DoubleAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="VisualPopRect"
                                  
Storyboard.TargetProperty="Opacity"
                                  
To="1" />
                                </Storyboard>
                               
                               
<Storyboard x:Key="Disabled State" >
                                    <DoubleAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="FaderRect"
                                  
Storyboard.TargetProperty="Opacity"
                                  
To=".2" />
                                    <ColorAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="FaderRectColor"
                                  
Storyboard.TargetProperty="Color"
                                  
To="Black" />
                                    <ColorAnimation Duration="0:0:0"
                                  
Storyboard.TargetName="BorderRect"
                                  
Storyboard.TargetProperty="(Rectangle.Stroke).(SolidColorBrush.Color)"
                                  
To="Black" />
                                </Storyboard>
                               
                           
</Grid.Resources>
                           
                           
<!-- creates the solid line "border" of the HyperlinkButton -->
                            <Rectangle x:Name="BorderRect"
                          
Width="{TemplateBinding Width}"
                          
Height="{TemplateBinding Height}"
                          
Stroke="{TemplateBinding Foreground}"
                          
Fill="{TemplateBinding Background}"/>
                           
                           
<!-- Container for positioning HyperlinkButton content -->
                            <StackPanel Orientation="Horizontal">
                               
                               
<!-- invisible rectangle used to leave space for the highlighter (VisualPopRect) -->
                                <Rectangle Width="{TemplateBinding Height}"
                               Height="{TemplateBinding Height}" />
                               
                               
<!-- HyperlinkButton content -->
                                <ContentPresenter x:Name="Normal"
                               Background="{TemplateBinding Background}"
                               Content="{TemplateBinding Content}"
                               ContentTemplate="{TemplateBinding ContentTemplate}"
                               FontFamily="{TemplateBinding FontFamily}"
                               FontSize="{TemplateBinding FontSize}"
                               FontStretch="{TemplateBinding FontStretch}"
                               FontStyle="{TemplateBinding FontStyle}"
                               FontWeight="{TemplateBinding FontWeight}"
                               Foreground="{TemplateBinding Foreground}"
                               HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                               Padding="{TemplateBinding Padding}"
                               TextAlignment="{TemplateBinding TextAlignment}"
                               TextDecorations="{TemplateBinding TextDecorations}"
                               TextWrapping="{TemplateBinding TextWrapping}"
                               VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                              
Margin="2,2,2,2" />
                            </StackPanel>

                            <!-- Focus indicator, inside dashed line -->
                            <Rectangle x:Name="FocusVisualElement"
                           Margin="2" Stretch="Fill"
                           Stroke="{TemplateBinding Foreground}"
                          
StrokeThickness="1" StrokeDashArray="1 2"
                           />

                            <!-- Objects for highlighting changing visual states -->
                           
                           
<!-- Rect to the left of the content -->
                            <Rectangle x:Name="VisualPopRect"
                           HorizontalAlignment="Left"
                           Height="{TemplateBinding Height}"
                           Width="{TemplateBinding Height}"
                           Fill="{TemplateBinding Foreground}"
                           Opacity="0"/>
                           
                           
<!-- Make the control appear faded -->
                            <Rectangle x:Name="FaderRect"
                           Width="{TemplateBinding Width}"
                           Height="{TemplateBinding Height}"
                           Opacity="0">
                                <Rectangle.Fill>
                                    <SolidColorBrush x:Name="FaderRectColor"
                                  
Color="White" />
                                </Rectangle.Fill>
                            </Rectangle>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>

 

Applying the Template

Using a ControlTemplate is as simple as using a Style... because a ControlTemplate is basically part of a Style.  Just use databinding to a StaticResource for linking the Style property to the ControlTemplate.  The following code shows three sample HyperlinkButtons: one without the ControlTemplate, one using the default ControlTemplate Values, and one overriding the ControlTemplate's default values. 

    <Grid x:Name="LayoutRoot" Background="White">
       
       
<TextBox Width="100" Height="20" FontSize="10" Margin="0,0,200,150" Text="Click &amp; Tab" />

        <HyperlinkButton Content="Default Appearance" Margin="0,0,100,50" Height="20" Width="200"/>

        <HyperlinkButton Content="Using ControlTemplate" Margin="0,50,100,0" Height="20" Width="200" Style="{StaticResource HyperlinkWithBorder}" />

        <HyperlinkButton x:Name="LinkToDisable" Content="ControlTemplate with inline properties" Margin="0,150,50,0" Height="20" Width="250" Style="{StaticResource HyperlinkWithBorder}" Background="PapayaWhip" Foreground="Sienna"/>
       
       
<ToggleButton Content="disable it" Margin="280,150,0,0" Width="60" Height="20" Click="Toggle_Click" x:Name="ButtonThatDisablesLink" ></ToggleButton>
   
   
</Grid>

And, finally, here is the Silverlight example you can interact with, to see how it looks when finished. 

  • To review the MouseOver state, move your mouse around the example. 
  • To preview the Pressed state, click on the links.
  • To preview the Disabled state, click on the button.
  • To preview the "has focus" state, click in the textbox and tab to the links.

If you can't see the Silverlight example, below is a screenshot that illustrates the unstyled HyperlinkButton with focus, the ControlTemplate HyperlinkButton with MouseOver, and the second ControlTemplate HyperlinkButton as disabled.

silverlight-simple-controltemplate

The ControlTemplate is a powerful tool.  It can be used to make drastic changes to the way your application looks.  For example, in the Solar Shooter game, I made buttons that look like a car, a lightning bolt, and an explosion.  ControlTemplates can be more difficult to build than Styles because they include more parts and also because they don't always throw errors - which makes debugging much harder.  But the extra work is worth it... and once you learn the concepts, it does get easier.  ControlTemplates are one of the Silverlight tools that have the potential to dramatically improve web applications.  What will you use them for?

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   Software Dev
Actions:   E-mail | Permalink | Trackback | Comments (1) | Comment RSSRSS comment feed

Silverlight Named Colors

Tuesday, 20 May 2008 21:40 by snyhol

One MSDN resource I use regularly is the page about named colors.  It is helpful when I want to quickly add a color to my application without going through the RGB color picker.  This reference is good because it provides a screenshot example of each named color, along with its official predefined color name and corresponding RGB values. 

This page is part of the Silverlight 1.0 documentation.  I use this one because I haven't found a similar reference for Silverlight 2.  Besides, the 1.0 color names still work in Silverlight 2.

It would be cool if Visual Studio provided color swatches in the IntelliSense.  Here's the current IntelliSense:

visual-studio-2008-silverlight-named-colors-intellisense

Here's what it could look like:

visual-studio-2008-silverlight-named-colors-intellisense-dream

Neither Blend nor Design support setting colors by their named values.  Of course, you can do this in XAML in Blend. 

Perhaps the lack of support for named colors is because most "real" designs will use colors defined by their RGB values.  It would still be cool to have this resource integrated into the tools rather than having to look it up from documentation. 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Silverlight Skinning with Style

Monday, 19 May 2008 16:19 by snyhol

While I was developing the Solar Shooter game, I wanted to add "control template and skinning support."  What is that?  Silverlight uses the "WPF-based" UI framework, which means that the appearance is separate from the behavior.  This is implemented through Styles and Control Templates.  They both provide a central place where you can define the appearance of a control.  Basically, Styles change one property of the existing appearance of the control, while ControlTemplates replace the entire appearance. 

Styles are very similar to CSS.  Styles can be used to customize the default appearance of a control.  The Silverlight SDK provides a very clear explanation of styles and is available online.  If you are completely new to Styles, read Jesse Liberty's Styles and Templates Tutorial.  For example, you can use a Style to make a group of TextBoxes have a yellow background.  Styles can be defined wherever you have <Resources> (i.e., control resources, grid resources, UserControl resources, App resources, etc.).  Basically, a Style is used to set a collection of properties for a specified type of control.  

As a simple example, let's use Styles to apply a green theme to a standard login form.  Though this example is very simple, it demonstrates using Styles to change the appearance of multiple controls from one place.  If we wanted to reduce the size of the labels to 13 points, we would only have to make that change in one place.  We can also feel confident that all of our labels have a similar appearance because they all use the same Style resource.

Here is a screenshot of the form before applying Styles:

silverlight-simple-style-no-style

Here's the code I used to apply a green theme to change the appearance of controls on this login form.  This example uses both named colors and RGB-defined colors to achieve a consistent visual design. 

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.Resources>
        <Style TargetType="TextBlock" x:Key="ColoredTextBlock">
            <Setter Property="Foreground" Value="SeaGreen" />
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="FontStyle" Value="Italic" />
            <Setter Property="FontSize" Value="14" />
        </Style>
        <Style TargetType="TextBox" x:Key="HighlightedTextBox">
            <Setter Property="Background" Value="MintCream" />
            <Setter Property="Foreground" Value="#164A2D" />
            <Setter Property="BorderBrush" Value="#164A2D" />
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="FontSize" Value="12" />
        </Style>
        <Style TargetType="Button" x:Key="HighlightedButton">
            <Setter Property="Background" Value="SeaGreen" />
            <Setter Property="Foreground" Value="#164A2D" />
            <Setter Property="FontSize" Value="14" />
        </Style>
    </Grid.Resources>
    <TextBlock Style="{StaticResource ColoredTextBlock}" Margin="10,30,0,0">Username:</TextBlock>
    <TextBlock Style="{StaticResource ColoredTextBlock}" Margin="10,65,0,0">Password:</TextBlock>
    <TextBox x:Name="UserName" Style="{StaticResource HighlightedTextBox}" Width="100" Height="25" Margin="10,0,0,20" Text="Demo" />
    <TextBox x:Name="Password" Style="{StaticResource HighlightedTextBox}" Width="100" Height="25" Margin="10,50,0,0" Text="****" />
    <Button x:Name="SubmitButton" Style="{StaticResource HighlightedButton}" Width="60" Height="30" Margin="210,50,0,0" Content="Submit" />
</Grid>

Here's the result of using Styles:

silverlight-simple-style-green-theme 

As you can see, Styles are an important Silverlight / WPF concept to know.  It might seem confusing if you haven't used them before, but they are really simple once you understand them.  Styles are a powerful way of organizing your code, making it easier to maintain, and also help to enforce a consistent appearance across your application(s).  Have fun coding with Style!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   Software Dev
Actions:   E-mail | Permalink | Trackback | Comments (0) | Comment RSSRSS comment feed

Silverlight 2 Features Used in My RIA Run Game

Friday, 16 May 2008 19:37 by snyhol

TECHNOLOGIES USED: Silverlight 2 Beta 1, Expression Blend 2.5 Beta, Expression Design 2 Beta, Visual Studio 2008

I decided to enter the RIA Run contest, mostly to learn Silverlight 2 while building casual games.  Since I was already learning how to make a "shoot'em up" type of game, I kept going with it - but added more interesting characters.  Upon reading the contest description and rules, I realized that this competition was perhaps more about showcasing the new features in Silverlight 2 than about the gameplay.  It makes sense - this is a Microsoft sponsored event and they always want to promote their new technologies.  For this version of my game, I made a strategic decision to focus more on the technology than on the gameplay. 

The game I made is called Solar Shooter: A Gas Guzzler's Nightmare.  Part of my score in the competition will be based on how many people play the game on the devx.com website.  As soon as I get my link, I will post it right here.  In the meanwhile, you can play the game on my new SL42.com games website

UPDATE: Solar Shooter was selected as a finalist!  From May 16 to June 5, 2008, support my entry into the contest by playing Solar Shooter at devx.com

Here's a brief description of the game:

Frustrated by the high gas prices at the pump? Blow off some steam playing “Solar Shooter: A Gas Guzzler’s Nightmare.” In this shoot’em up arcade game, it’s you vs. the gas guzzlers. Use your solar powered, electricity shooting hover car to face off against the single occupant commuter, the angry guy in the SUV, and even the dreaded gas station pump. Gotta zap them before they soak you.

The entry form asked me to briefly describe "How does this game use Silverlight 2.0 Beta features? What quirks, tips, or gotchas did you uncover?"  They were looking for a short description... but I had way more to say about Silverlight 2 features than could fit into 60 words.  Below is my complete list. 

Silverlight 2 Beta 1 Features Used in Solar Shooter

Managed code.  The application was built entirely within the Silverlight framework.  No HTML or Javascript needed.  BCL and CLR all the way!!!  Three cheers for events, delegates, strongly typed objects, object inheritance and composition. 

Layout Management.  The game makes extensive use of the built-in layout management controls (i.e., Grid, StackPanel, Canvas) in addition to the built-in layout management capabilities. 

  • RotateTransforms are used for rotating the game characters (also known as "sprites")
  • TranslateTransforms are used to add a shadow to text
  • A ScaleTransform is used to resize the game when it's parent browser window resizes
  • A Border was used to create rounded corners on for the in-game score
  • ZIndex, Opacity and Visibility are used to manage the dynamic display
  • Margin is typically used to position objects within a grid cell.  To remember what the 4 numbers mean when setting margins in XAML (i.e. Margin="4,12,30,2") - think of the acronym "LTRB," which sounds like "Letter B," and is short for Left,Top,Right,Bottom.

Data Binding.  The game uses databinding whenever possible to simplify connecting the UI to several data sources.

  • Two-Way data binding is used to manage the audio effects.  The MediaElement playing the sounds is bound to a toggle button that can be used to mute them.  Since there is no way to automatically databind the two properties directly, I made a bindable CLR class (implements INotifyPropertyChanged) that acts as a binding surrogate to connect them. 
  • One-Way data binding is used for the score and level text in TextBlocks.  In both cases, I wrote Converters to change the data content into text to show on screen.  For example, one converter modifies the score to include the thousands separator. 
  • One-Way data binding is also used to display the ObservableCollection of high scores in a DataGrid.  A Factory Pattern is used to allow for multiple scoreboards (i.e., local, server, etc.)

Control template and skinning.  This game uses both Styles and ControlTemplates.

  • Styles are used to format the text on the instructions page.
  • ControlTemplates are used to make the custom round buttons for Mute, closing the instructions / high score screens, on the pause screen and on the game over screen.  They were also used to make irergular shaped buttons on the main screen.  The button on that screen are shaped like a car, lightning bolt, and an explosion. 
  • ControlTemplates are also used to provide animated effects for events like mouseover or pressed.   
  • Making templates from Expression Design was harder than I would have liked... but much easier than trying to hand-code the vector graphics.  Some of the gotchas I encountered while exporting the graphics follow. Inside a ContentTemplate, you cannot have two controls with the same x:Name... but Design likes to export XAML with the x:Name specified.  I found it easiest to export the entire graphics for the different states of my controls... leave them in the <Canvas> objects as exported by Design... and toggle the opacity of those Canvas objects in the event storyboards.  Probably not the best performance - fairly fast to build!

Core Form Controls.  Several controls are used in making this game. 

  • TextBlocks are used for the current score, level transitions, game over screen, and instructions screen. 
  • Buttons are used for most user interaction: show screens, start a new game, etc.
  • A WatermarkedTextbox is used to get the user's name for display on the high scores list.
  • A ToggleButton is used to allow the user to mute the sound.

Build-In Layout Management Controls.  The game makes extensive use of Canvas controls (included in Silverlight 1.0) as well as the newly introduced Grid and StackPanel controls.

  • The Canvas is the lightest weight control and I used it whenever I could.  It's worth pointing out that it is also the only layout control with a ZIndex attached property.
  • The Grid makes some layout tasks extremely simple and is used as the main "LayoutRoot" container.  The Rows and Columns are used for placing the items in the top bar (score + lives), side bar (volume control), and bottom bar (links).
  • The StackPanel is used whenever items could just flow down or across the screen... for example the "number of lives" indicator.

Common Functionality Controls.  The game used other controls where it made sense. 

  • MediaElement is used to play the background music and also could be used for character sounds.
  • Hyperlink buttons are used to provide the game player with access to information from another website.

Data Manipulation Controls.  Games typically don't use as much data as business applications, so there isn't much need for controls that handle data.  However, the "high scores" listing does provide one place to show off some data manipulation.

  • A DataGrid is used to display data from multiple objects (score and user objects).  Through databinding, the underlying data source could be edited by adding a new score at the end of a game or deleting a score by pressing the DELETE key. 

Collections.  Collections are used for keeping track of game objects and databinding the saved scores.

  • Managing game objects (sprites) was done by adding and deleting them from a List<SpriteBase> collection.
  • One trick to get around was dynamically re-sorting an ObservableCollection when adding a new item.  I created a new subclass to handle this functionality.

I/O & Local Storage. Scores are saved to the computer in a persistent location.  In other words, they are available across browser sessions.

  • Saving scores to the computer uses a Silverlight concept called Isolated Storage.  This is functionality a programmer can use to access a sandboxed location on the user's hard drive.  Data can be saved to the disk and retrieved from the disk using I/O operations.  To imlpement this functionality, I use IsolatedStorageFile, IsolatedStorageFileStream, StreamReader, and StreamWriter objects.
  • Local storage is also used to save user settings between sessions.  Specifically, the ApplicationSettings object is used to save the player's name.  It was tricky to store a CLR object in both a bindable Resource (defined in XAML) and in the ApplicationSettings.  Basically, I had to use the Decorator Pattern to consolidate the functionality.  Also, only serializable objects can be put in the ApplicationSettings.

Generics.  Generics are a useful tool in making comlpicated coding tasks simpler.

  • Generics are used to help in managing the collections of game characters (sprites).  For example, the collection that kept track of the enemies on the screen is defined as a List<SpriteBase>... but contains several types of objects: EnemyOilBarrel, EnemyGasTanker, and EnemyGasCan. 
  • Generics are used with databinding to a collection. 

Threading. The new DispatcherTimer class was THE fundamental concept behind making this game work.

  • In Silverlight 1.0, developers would use a Storyboard object to manage the game loop (the core component of the game engine that makes sure game actions happen smoothly.
  • This game uses the Silverlight 2 DispatcherTimer class to run the game loop.  DispatcherTimer is used to run a Timer object on the UI thread.  The Interval is set to TimeSpan.FromMilliseconds(0) for automatically smooth animations.  The Tick event is used to manage critical actions, like making random enemies, making hero and enemy ammo, moving heroes, enemies, and ammo, collision detection, handling user input (keystrokes) and also initiating game events like changing levels.
  • A wrapper class is used with the DispatcherTimer to convert game action to elapsed time, making the gameplay independent of CPU speed. 

Globalization. This game incorporates globalization by creating a framework for globalization and showing culturally specific number formatting on the current score and in the high scores table.

  • The game integrates with ASP.NET for initial globalization support.  ASP.NET is used to retrieve the culture settings from the browser and pass them to the Silverlight plug-in's Init property.  The Silverlight project grabs the setting in App.xaml and stores the browser-based culture setting in an application Resource.  It also sets the UserControl's Language DependencyProperty.
  • This framework can be expanded by incorporating RESX resource files to globalize the text displayed on screen.  All text was displayed in bindable TextBlock controls to aid in this effort.  No text was stored inside a graphic (in Expression Design, select Export Text as TextBlock).
  • This framework can also be extended to allow the user to override the initial culture setting by selecting another language from a Configuration or Main Menu screen. 
  • Note that the DataGrid showing a date inside a TextBlock automatically formatted the date to comply with cultural sensitivity.  I did not have to add code to explicitly format the dates.  I just had to set the current culture in the UserControl's Language DependencyProperty. 

LINQ to XML. The game uses XML to store the scores in the Isolated Storage. 

  • To simplify the serialization and deserialization of data stored to the Isolated Storage, LINQ to XML is used.  I found the XDocument object model easier to work with than XMLWriters for serialization.  Pulling out the data was even easier with a XDocument.Parse() method to extract the XML tree and then a LINQ query to convert it to CLR objects.

OOP.  This game makes use of some object oriented concepts. 

  • Interfaces were used to support the creation of different scoreboards.  For example, one scoreboard could use scores saved to "my computer" and a different scoreboard could use scores saved on a public server.
  • Inheritance is used on the UserControls to consolidate the common base functionality for sprites.  Since they are visual elements, putting them in UserControl containers made sense.  This approach was tricky to implement and worked, but meant losing designer support in Expression Blend for any subclassed UserControl. 
  • A Decorator Pattern is used to consolidate an object defined in the UserControl.Resources markup with an object saved in the IsolatedStorage with ApplicationSettings. 

Keyboard Input.  The game action interacts with the user via keyboard input. 

  • The System.Windows.Input.Key enum was added in Silverlight 2 and it is nice! 
  • Since keyboard input is used, the application cannot be run in true "FullScreen" mode.  Silverlight does not allow keyboard input while in FullScreen.  A workaround for this is using 100% of the available browser window and letting the user maximize the browser.

Mouse Input.  The game uses mouse input mostly for administrative tasks. 

  • Mouse events are used to capture button clicks. 
  • Mouse actions are automatically captured by the HyperlinkButtons.

Attached Properties, Dependency Properties, etc. 

  • Attached Properties are commonly used in conjunction with layout management support.  They are seen in properties like Canvas.Top.
  • Dependency Properties are used in data binding situations, using framework methods like GetValue and SetValue. 

XAP Packaging.  This game was deployed as a XAP compressed file.

  • The XAP package was analyzed for size in KB.  This was an important task because a smaller download size makes the applications more accessible to users with slower Internet connections.  Here are some tips for reducing the XAP size:
    • Use Expression Design tricks to compress the XAML graphics. 
    • Remove unneeded project references, like Syndication or XMLSerialization.
    • Leave media files outside the XAP by marking them with a Build Action of None and Always Copy to the output directory.  Manually copy them to the deployment server.  This will increase the load time for your application because media files are typically not needed when the application first loads.

Audio Support.  The game uses audio files to play background and special effects music.

  • The audio files are converted to compressed WMA format using Expression Encoder 2 Beta. 
  • The files are deployed to the server outside the XAP.
  • The media is played using a MediaElement file.  It is bound to other controls/objects, looped for continuous playback, and played from code in response to an event.
  • The audio files must be compressed in a compatible format.  Expression Encoder is a good tool for the job.  I got media errors when trying to play MP3 files compressed in Audacity.

Number Formatting.  The number formatting classes of the framework are used to display the current score in a culture-specific manner.

C# Automatic Properties.  For simple properties, my custom classes use the { get; set; } syntax.

C# Implicitly Typed Variables.  For the LINQ to XML code, the var keyword is used to create imlicitly typed variables.

Error Handling.  To assist in development and error reporting, I use global error handlers. 

  • A global error handler is used in the App.xaml class: Application_UnhandledException
  • The plugin also provides an interface to pass errors to a JavaScript function. 

Backgrounds: No DrawingBrush.  A simple method to add a fancy background is to put vector graphics in a resource that is added as a DrawingBrush.  Since Silverlight does not include this object, a workaround was to put the graphics in a container (UserControl, Canvas, etc.) and place that container behind everything else using the ZIndex property.

2D Animations.  Aaah, one of the cornerstones of a Silverlight application. 

  • Storyboard objects are used to animate the level transitions, the blinking car crash, the explosions, and much more.  The Storyboards in this came are defined with DoubleAnimationUsingKeyFrame and SplineDoubleKeyFrame objects.
  • Game characters (sprites) are manually animated by setting their Canvas.Top and Canvas.Left attached properties to move them around the screen (game surface).

2D Vector Graphics.  To take advantage of application resizing, all graphics in this game are vector graphics created in Expression Design.

  • Rectangle, Ellipse, and Path objects are used to draw the graphics.  Path mini language was frequently used
  • LinearGradientBrush, RadialGradientBrush, GradientStop, Fill, Stroke are used to modify the appearance of the shape objects.

Text.  Text is rendered through a variety of controls. 

  • TextBlocks show read-only text, TextBoxes interact with the user, DataGrid and Buttons display other text for user interaction.  Common formatting properties are used, like font size, alignment, font family, and font weight.

Garbage Collection. 

  • The C# Using statement is used when working with Isolated Storage.  The Using statement improves garbage collection, automatically making calls to the Dispose method.

 

End To End Experience with Expression Studio

Visual Studio 2008 is a good tool for writing code and also for writing XAML markup.  However, it is not a strong tool for creating the dynamic layout, animations, fancy graphics, and multimedia necessary in a good game.  For those tasks, Expression Studio makes a good complimentary toolset.  Below are brief descriptions of my experiences using these products while making Solar Shooter.

Expression Blend 2.5 Beta.  This tool was used alongside Visual Studio to develop the application. 

  • It was better than Visual Studio when performing layout or animation tasks.  It provides a rich controls palette and the properties panel was a good place to discover what I could do to a control.  For editing raw XAML and C# code, Visual Studio was better (it includes intellisense for XAML!!).
  • Be cautious when using both tools simultaneously!  It is easy to overwrite edits in one program with the other. 
  • Blend provides an interactive designer surface, which provides a much nicer design experience than the current read-only designer in Visual Studio. 
  • The Blend designer tends to throw more errors about the underlying CLR classes than the Visual Studio designer or even the runtime.  For example, Blend expects Resources to either subclass from DependencyObject OR use the x:Key declaration. 
  • Blend has an awesome feature that translates layout controls.  For example, you can convert a Canvas containing vector graphics absolutely positioned with Top and Left coordinates into a Grid with positioning done by Margin.

Expression Design 2 Beta.  All graphics used in this game are vector graphics created in Expression Design. 

  • Expression Design is a much better tool than Expression Blend for creating and editing graphics.  It is much more powerful and provides a more efficient design experience. 
  • Since Expression Design 2 Beta was built to comply with Silverlight 1, importing the graphics as Silverlight XAML was not a completely smooth process.  The XAML exported by Design needed to be manually edited to comply with Silverlight 2. 
  • To optimize the export size from Expression Design, do not name objects, do not place objects in XAML layout containers, and leave text as Editable TextBlocks.  Also, when building the objects, try to use the simplest shapes possible, minimize the number of nodes on paths, and avoid fancy Strokes.  Using bitmaps (in "live effects", Fill, Stroke, etc.) might lead to unpredictable behavior when exporting to XAML vector based graphics. 
  • To facilitate globalization, all text must be editable by code.  Ideally, no text would be embedded in bitmap graphics or converted to paths in vector graphics.
  • One gotcha I discovered was that your vector graphics may extend outside of the slice and Design tries to solve this by putting a clipping mask on the parent canvas. 

Expression Encoder 2 Beta.  The audio files were converted to WMA format and compressed with Expression Encoder. 

  • I was impressed with Encoder's interface.  I was able to easily compress the audio files using WMA settings 16kbps bitrate, 22kHz sample rate, 16 bits per sample, and Mono channels.  The compression rivaled MP3 compression from other programs... and worked seamlessly with Silverlight.

 

More Silverlight 2 Features

As if I didn't already use enough features, here are more that I would have implemented if I had more time:

  • Use a Checkbox control to filter the scoreboard to only show my scores.
  • Making the DataGrid (scoreboard) be re-sortable.
  • Use two DatePicker controls to filter the scoreboard to only show scores within a certain date range.
  • Use a Slider control to adjust the difficulty of the game.
  • Use a ListBox control to allow the user to change their language.  (A DropDown control would be better, but that control was not included in Silverlight 2 Beta 1.)
  • Use the FileOpen dialog to upload an avatar (picture) from the user.  Show that avatar on the scoreboard.
  • Use Cross Domain Network Access (sockets) to allow people to create game groups with private scoreboards that update each other.
  • Use HTTP Networking and WCF Services to provide a global public scoreboard that is hosted on the server.
  • Use JSON for passing data across networks, since it is lighter weight than XML.
  • Use Asynchronous Programming with sockets, networking, and perhaps with downloading media. 
  • Use Cryptography to cache and encrypt user information.
  • Extend the usage of Globalization to also globalize text (it currently just "localizes" number and date formatting).
  • Use HTML DOM / JavaScript Interop for... wait a minute! This is a managed-code application!  Screw the interop!

 

Conclusion

Whew!  I put a lot into this game.  Looking back on this process, I can see that I did learn a lot about getting the most out of Silverlight 2.  It is a very powerful framework that met most of my needs. 

What's next?  I'm going to learn and incorporate more features into this game.  I also plan on enhancing the gameplay with boss characters, special weapons, more sound effects, and more storyline.  The updated version will be posted to the SL42.com website. 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Becoming a Devigner

Wednesday, 30 April 2008 08:46 by snyhol

People who can create an attractive UI (like a designer) and write code (like a software developer) are getting called various names... a lot of new names, like dev-igner, des-eloper, design-loper, designer-developer, creative developer, or integrator.  My favorite is "devigner." 

A devigner is someone who can work on both sides of the designer-developer workflow. Devigners have been described by Adam Kinney as people who design and develop, by Ryan Stewart as people who move seamlessly between their development tools and their design tools, by Heather Solomon as people who can bang out CSS and pretty graphics and turn around and fix the UI in C# code, can do up a fine front end, but actually understand the backend, and by Kevin Tate as someone how is in-between a 'designer' and a 'developer,' a design/developer hybrid.  Fernando Comet even declared the 5 Commandments of a Devigner.  

Here is my list that defines the skills needed to call yourself a well rounded devigner:

  • Emphasizes the user experience (UX)
  • Can create UI code
    • Uses "developer" or "designer" tools
    • Makes CSS, HTML, XAML, Flash, etc.
  • Can create backend code
    • Uses "developer" tools
    • Makes UI logic, business rules, database and web service interaction, etc.
  • Can create artistic graphic designs and has a good "design sense"
    • Uses "designer" tools
    • Makes bitmap graphics, vector graphics, etc.

In other words, a devigner is someone who is is skilled in UX, UI, software engineering and graphic design. 

How do you become a devigner?  Get training & experience in those four areas. 

What am I doing to become a well rounded devigner?

  • I've emphasized usability for years (i.e. Don't Make Me Think)... DONE
  • I've worked on UIs for years (both windows and web, now WPF and Silverlight)... DONE
  • My primary skillset is software development with Microsoft technologies (MCSD + MCDBA)... DONE
  • I've dabbled a little with Photoshop, GIMP, Paint.NET, Fireworks... FOCUS HERE!
To round out my devigner portfolio of skills, I am enhancing my design skills, specifically with the Expression suite of "designer" tools.  Expect to see some posts about them! 

With the industry's current emphasis on designer-developer workflow, there will be demand for devigners who focus on building good UX and are competent with both developer tools, like Visual Studio, and designer tools, like Expression Studio.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:   , ,