Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

WPF Dartboard scoring application

  In this article I'll review the steps to creating a WPF-based touch-screen scoreboard application that we use in our Clarity Cricket recreational dart league. In doing so, I'll show some examples of how to create custom animations in Visual Studio .NET and wire them up to StoryBoards in XAML
Clarity Consulting, Inc.

Difficulty: Advanced
Time Required: Greater than 10 hours (to build custom animations)
Cost: Free
Software: Microsoft Visual Studio 2005 .NET Framework, 3.0 November 2006 CTP of the Visual Studio 2005 extensions for .NET Framework 3.0, Microsoft Expression Blend 2 May Preview
Download: Source code
In this article I'll review the steps to creating a WPF-based touch-screen scoreboard application that we use in our Clarity Cricket recreational dart league.  In doing so, I'll show some examples of how to create custom animations in Visual Studio .Net and wire them up to StoryBoards in XAML

Back in October one of my co-workers at Clarity, Kevin Marshall, wrote an article about how he modified the foosball table in our employee lounge to allow us to track game results and individual player statistics (see article here). Statistics are the basis for bragging rights, and at a competitive software development company, we're big on bragging rights. Following in the tradition of the foosball, we next set out to make similar capabilities to track scoring and statistics for our recreational dart board. We ended up building a WPF-enabled windows form-based application to use as our virtual scoreboard, attached it to a touch screen monitor, and hooked it up to a database to track statistics. This article will show how we went about building a Cricket scoreboard application. 

Since the application makes heavy use of animations, a video works better to convey some of the features.  You can view a video of the dart board application in action here.

Windows Presentation Foundation

Windows Presentation Foundation (WPF) is Microsoft's next generation framework for building rich user experiences for both forms-based and web-based applications. At the core of WPF is the Extensible Application Markup Language (XAML – pronounced “Zamel”) which allows developers to lay out a user interface using XML in a hierarchical tree structure. If you're not familiar with WPF, you may want to stop reading this article and first read an overview of WPF on MSDN. This article assumes you have a basic understanding of the concepts of WPF. I built the application in this article using the November 2006 CTP of the Visual Studio 2005 extensions for .NET Framework 3.0. Make sure you install the .NET 3.0 runtime prior to installing the Visual Studio extensions.

Laying out the main form

In support of WPF, Microsoft has released a slew of tools that make writing WPF applications easier. Expression Studio is a suite of tools that Microsoft market's towards “creative designers”, but these tools are equally important for developers, especially with the WPF framework's designer glitches in the current release. In many cases you cannot use the designers built into Visual Studio. For example, if your forms use controls that you create, you will not be able to open your XAML file in the visual designer in Visual Studio. To get around this, you can use Expression Blend to open your Visual Studio project and view your form (Expression Blend can natively open Visual Studio project and solution files).

Scoreboard_Expression2

Figure 1: Microsoft Expression Blend XAML editor

Expression Blend is great for editing XAML and creating Storyboard (animations) but it is important to note that the tool is not a code editor.  You cannot edit the .NET code behind files or even HTML or Javascript files from within Expression Blend.  However, there is nice integration with Visual Studio .NET - opening a code file from within Expression Blend will automatically kick off an instance of Visual Studio, open your solution, and present you with the source file to edit.

Our application contains just a few screens - the main dartboard form, plus a couple forms used to manage the players in the game and view statistics. Our scoreboard application will be run in a kiosk and use a touch screen monitor as the main interface. The idea is that a player throws the dart, and then touches the appropriate section of the screen to indicate where the dart landed. The scoreboard then tracks the score and statistics based on the accumulated data.
To create the main form I started with a vector image of a dartboard and used Expression Design to export the image to XAML. The vector image consists of paths for each individual component so the resulting XAML will contain the details for each path. Below is a sample snippet from a one of the Path elements in the scoreboard's XAML. Each individual Path element makes up a second of the image.

<Path x:Name="Path" Width="93.8075" Height="113.784" Canvas.Left="120.154" Canvas.Top="641.654" Stretch="Fill" Fill="#FFFF1A00" Data="F1 M... />

Once I have the XAML representation of the board, I can rename the individual Path elements and make them “clickable” by simply adding the appropriate attributes to each Path element, and then writing the event handler in the code behind file. In this case, I added the OnLeftMouseUp attribute to each Path element which would be raised for each section whenever the player clicks on the board.

<Path x:Name="Double16" MouseLeftButtonUp="Double16Click" Width="93.8075" Height="113.784" Canvas.Left="120.154" Canvas.Top="641.654" Stretch="Fill" Fill="#FFFF1A00" Data="F1 M... />

In the example Path above – the Double16 – the resulting code behind that would handle the event looks like this:

C#
        void Double16Click(object sender, EventArgs e)
        {
            OnDartThrown(Darts.Dart16, 2);
        }
VB
        Private Sub Double16Click(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
            OnDartThrown(Data.Darts.Dart16, 2)
        End Sub

The OnDartThrown method simply performs a swtich on the Dart enum and performs the appropriate animation followed by notifying the game class to record the score.

Scoring and Rules

Since we envision using this framework to support multiple dart games, we created a BaseGame class and derived a CricketGame class from BaseGame. Our scoreboard has a member variable of type BaseGame that is set to an instance of the current game type (note: we didn't implement multiple game types yet –that could be done by adding an additional screen to choose the type of game to play – so for this version all games are of type Cricket). Our BaseGame has a virtual method called UpdateGame that is called after every dart is thrown. This gives the game class a change to update any game data, player scores, statitistics, or other state as required. Since our game is Cricket, CricketGame class manages the scoring rules specific to Cricket, such as maintaining open/close state of each target number:

C#

   if (lastDartThrown != Darts.DartOutOfBounds)
   {
       score = UpdateScores(lastDartThrown, numberThrown);
       UpdateClosedStatus(lastDartThrown);
   }

   List<int> dartMarks = _players[_currentPlayerIndex].MarkDart(lastDartThrown, numberThrown);
   _dartHistory.Push(new DartHistoryItem(score, lastDartThrown, numberThrown,wasClosed, _currentPlayerIndex, _round, dartMarks));
VB
        If lastDartThrown <> Darts.DartOutOfBounds Then
            score = UpdateScores(lastDartThrown, numberThrown)
            UpdateClosedStatus(lastDartThrown)
        End If
        Dim dartMarks As List(Of Integer) = _players(_currentPlayerIndex).MarkDart(lastDartThrown, numberThrown)
        _dartHistory.Push(New DartHistoryItem(score, lastDartThrown, numberThrown, _
        wasClosed, _currentPlayerIndex, _round, dartMarks))

Setting up the animations

One of the key new capabilities WPF gives to developers is a way to add animations to their applications. For the dartboard framework, we wanted to add animations after each scoring throw. To give us a good variety, we played around with several different types of animations as part of the storyboards in our application.  For the dartboard scoreboard we built custom animations for various events that occur during the game – scoring throws, transitions between the scoreboard and the settings screens, and transitions between rounds during the game. We implemented our animations in .Net and referenced the .Net classes from within the XAML by adding a namespace declaration in the root node of our scoreboard XAML file. Referencing .Net code from within XAML (and also referencing XAML-defined elements from within .Net) is an important concept to understand when writing complex WPF applications.

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:uc="clr-namespace:DartScoreboard.GUI.Controls" 
    xmlns:CustomAnimations="clr-namespace:DartScoreboard.Animations" .../>

With the namespace for our custom animations declared, we can reference them via storyboards in the XAML. For example, the XAML below is a storyboard that refers to our BounceDoubleAnimation.

      <Storyboard x:Key="roundChangedAnimation" SpeedRatio="2.0">               
              <CustomAnimations:BounceDoubleAnimation
                    From="-500" To="0" Duration="0:0:5" EdgeBehavior="EaseOut" 
            Storyboard.TargetName="roundChangedBounce" 
            Storyboard.TargetProperty="(TranslateTransform.Y)"/>
      </StoryBoard>
 

This animation is used during the transition from one round to the next, and results in the text bouncing as it moves from the top of the screen to the bottom.

DependencyProperties

One of the steps in implementing the animation in a .Net code-behind class is to define DependencyProperties. DependencyProperties are special types of properties that can be used by WPF to perform things like data binding, animations, inheritance, and styling. It is DependencyProperties, for example, that allow the WPF runtime to render the styling of a child element based on where it is nested in the XAML tree.  For our custom animations, any properties we want to add to our classes that affect or control the animation behavior must be defined as DependencyProperties.  For example, our BounceDoubleAnimation has a property called EdgeBehavior that controls whether the animation starts on the screen and moves off the screen (EdgeOut) or starts off the screen and moves onto the screen (EdgeIn).  We define this as a DependencyProperty below.

Creating a DependencyProperty in your code required two steps: First, you need to register the property with WPF. Second, you need to define property Get and Set methods that call the special GetValue and SetValue functions used to read and write DependencyProperties. The example below shows how to register the “EdgeBehavior” DependencyProperty used by the BounceDoubleAnimation:

C#

 

        public static readonly DependencyProperty EdgeBehaviorProperty =
            DependencyProperty.Register("EdgeBehavior",
                typeof(EdgeBehaviorEnum),
                typeof(BounceDoubleAnimation),
                new PropertyMetadata(EdgeBehaviorEnum.EaseInOut));
VB
        Public Shared EdgeBehaviorProperty As DependencyProperty = _
            DependencyProperty.Register("EdgeBehavior", _
                GetType(EdgeBehaviorEnum), _
                GetType(BounceDoubleAnimation), _
                New PropertyMetadata(EdgeBehaviorEnum.EaseInOut))

This snippet below shows how to create the property Get and Set methods for a DependencyProperty. Notice the calls to the GetValue and SetValue methods. 

C#

        /// <summary>
        /// Specifies which side of the transition gets the "bounce" effect.
        /// </summary>
        public EdgeBehaviorEnum EdgeBehavior
        {
            get
            {
                return (EdgeBehaviorEnum)GetValue(EdgeBehaviorProperty);
            }
            set
            {
                SetValue(EdgeBehaviorProperty, value);
            }
        }
VB
        Public Property EdgeBehavior() As EdgeBehaviorEnum
            Get
                Return CType(GetValue(EdgeBehaviorProperty), EdgeBehaviorEnum)
            End Get
            Set(ByVal Value As EdgeBehaviorEnum)
                SetValue(EdgeBehaviorProperty, Value)
            End Set
        End Property

Invoking Animations from managed code

Like most things in WPF, animations can be defined declaratively in the XAML, or via managed code.  Similarly, they can be triggered from within the XAML, or dynmaically from .NET.  In this case, we've defined the animations in Storyboard elements in the XAML, but we'll call them from .NET (for example, as a result of a dart being thrown).  It is easy to get a reference to a Storyboard and invoke methods against the managed Storyboard class: 

C#

        private void AnimateDoubleBull()
        {
            Storyboard doubleBullAnimation = (Storyboard)FindResource("doubleBullAnimation");
            doubleBullAnimation.Begin(this);
        }
VB
        Private Sub AnimateDoubleBull()
            Dim doubleBullAnimation As Storyboard = CType(FindResource("doubleBullAnimation"), Storyboard)
            doubleBullAnimation.Begin(Me)
        End Sub

Putting it all together

While all the WPF related features were fun to build, the real purpose of the framework is to track statistics. For our purposes we will track the typical win/loss record, plus player efficiency, which is the ratio of darts thrown to scoring throws. Since a “scoring throw” has a different meaning depending on what game is being played, we write the code to handle scoring in the derived BaseCricket class. For example, for Cricket we define a scoring throw as any throw that hits a 15 or higher, or a bullseye. We store this per player in a simple database and then compile statistics on the most efficient players. This isn't perfect of course but it works well for what we wanted. With a little work (and some interruption to the game's flow), you could compile statistics on a per target level to answer questions like who is the best at hitting the triple 20.

With the game framework coded and looking good we next looked to find a good place to position the touch screen monitor. We wanted a place that was convenient to the thrower, but yet not in the way. At first we mounted the monitor on the wall adjacent to the thrower. This worked well but we didn't have a good place to put the PC. We eventually ended up building a kiosk to house the PC with an angled top containing the touch screen monitor.

P6190002 P6190004

This made the whole presentation seem a little nicer and with the addition of some color and a couple Clarity logos it could make a great conversation piece when it comes to recruiting.



		

Tags:

Follow the Discussion

  • Dave BostDave Bost

    The boys at Clarity Consulting always seem to be on the bleeding edge of technology. Why is that they

  • Steve SinclairSteve Sinclair

    Cool!

    Missile Command will be next?

    What brand of touch Screen monitor did you guys use?  I am developing something that will need touch screen in wpf.

    -Thanks!

  • AnthonyAnthony

    Looks like a cool app - would like to build and try it out but it's looking for an assembly called PresentationDesignDeveloper - I have the WPF extensions installed and .Net Framework 3.0 but can't find this assembly? Any ideas?

  • 10,000 Monkeys - Harnessing the Power of Typing Monkeys10,000 Monkeys - Harnessing the Power of Typing Monkeys

    &#xA0; One of may favorite things on the iPhone is the scrolling lists. Actually it's hard to choose...

  • drefeappydrefeappy

    You don't really need or want that lifestyle, it might hurt y'all slowly more.......Just tell him you

    don't wanna repeat something your not too proud of z7uas.

  • Clint RutkasClint I'm a "developer"

    @Sam and @scromer:  will this work for you?

    http://www.mikeswanson.com/xamlexport/

  • scromerscromer

    How did you import a eps file into Expression Design? I tried it and it doesn't allow me to. I need to get a logo in eps vector format embedded into my WPF form.

    Thanks.

  • SamSam

    Great article, I have a question though. I have Expression Design and my eps vector image but Expression Design doesn't import eps images so how did you get it into Ex Design to export to Xaml?

  • 10,000 Monkeys - Harnessing the Power of Typing Monkeys10,000 Monkeys - Harnessing the Power of Typing Monkeys

    Writing blog posts just keeps jumping down the list. I think I need to realize that regular blogging

  • DaveDave

    Great work! I need a simpler code in VB that will just throw a dart on the DartBoard, Any idea?

  • CurtisCurtis

     Very nice work. I am just a bigginer at vb programing and was just looking around. An idea came to me and I dont know how feasible this would be but How about taking snapshots from a web cam of the dart board keyed by a sensor when the dart hit and using the image info to generate where the dart hit on the board. This would automate the input of data. Of course the dart would have to be of a color that is not in the dart board so that the image in the graphics object can be scanned for that color and position. This would of course be major project. I by no means have the understanding are knowledge to do something like this. I see that your team likes a challenge. So I decided to post this.

    PS There is a lot that may be beyond what is capable in the programming software. My understanding of programming is very limited.

  • Clint RutkasClint I'm a "developer"

    @Curtis, it is possible but would require some work.  I'd also think multiple cameras would be needed.

  • GoodGood

    Cannot create instance of 'PlayerChooser' defined in assembly 'DartScoreboard, Version=1.0.3686.28231, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation.  Error at object 'playerPanel' in markup file 'DartScoreboard;component/gui/forms/start.xaml' Line 76 Position 7.

    error come.

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.