The Silverlight Stopwatch
Microsoft's Silverlight framework (formerly WPF/E) allows you to build RIAs that run within the browser. The client runtime setup installs browser plug-ins, which enable you to embed Silverlight applications into web pages. Silverlight competes directly with the Adobe Flash platform.
At the time of writing, Silverlight supported Internet Explorer and Firefox on Windows, and Safari and Firefox on Mac OS X. It did not support Opera and Safari on Windows and offered no official support for support Linux (nor any plans for it). As you might expect, Microsoft does not offer any Silverlight development tools for platforms other than Windows either. However, the Moonlight project already has a Mono-based implementation of Silverlight running on Linux. That addition will provide Silverlight with the same level of platform compatibility as Flash.
Setting Up Development Environment
Take the following steps to set up the development environment for Silverlight:
- Install the Silverlight 1.1 Alpha runtime.
- Install the Silverlight 1.1 Alpha SDK.
- Install Microsoft Visual Studio (Codename "Orcas").
- Install Silverlight Tools Alpha for Visual Studio (Codename "Orcas").
- Launch the Visual Studio IDE, go to File->New->Project…, select Visual C# -> Silverlight project type, and pick the Silverlight Project template.
- Enter "stopwatch" as the project name and click OK. Your new project should look like Figure 3.
Building UI from the Original Artwork
Visual Studio will create a complete project framework for you. Press F5 to verify that the empty project compiles and runs. It should open a browser with a blank page. The page isn't really blank though; your Silverlight application is embedded in itbut the application has no visible elements yet. Before adding something there, download the accompanying Silverlight Assets source code and extract it into the "assets" subfolder inside your source folder. To display images, add the following line to Page.xaml within the <Canvas> tag:
<Image x:Name="mainBg" Source="assets/sport_bg.png"
Press F5 again and you should see a stopwatch background rendered in the top left-hand corner of the page. Now add two buttons to position them in a specific area:
<Image x:Name="btnClear" Source="assets/clear_btn.png"
Canvas.Left="185.50" Canvas.Top="188.35" />
<Image x:Name="btnStartStop" Source="assets/start_btn.png"
Canvas.Left="192.00" Canvas.Top="11.85" />
Next, add the digital display, which consists of two elements: a rectangular background with rounded corners and a text label:
<Rectangle Canvas.Left="83" Canvas.Top="154"
Fill="#2d2d2d2d" Width="69.32" Height="16.48"
RadiusX="5.82" RadiusY="8.24" Stroke="#6d551c"
FontSize="11" TextWrapping="NoWrap" />
Compiling and executing the project will display the complete stopwatch interfaceexcept for the hands. Unfortunately, the Image object doesn't support vector images (in particular, SVG), so if you try to feed it assets/hand.svg it will throw an exception at run time. One way around this is saving the hand as a PNG image and hoping that it will look fine. It won't.
A better solution is converting SVG into XAML. Both are XML based and similar in architecture, so it's quite easy to write a converter. If you have Adobe Illustrator, it's probably easiest to use the XAML Export plug-in for Adobe Illustrator (developed and maintained by Mike Swanson). In real-world applications you are better off using the Adobe Illustrator plug-in because it supports Silverlight and Microsoft authoring tools such as Expression Design (hopefully it will support SVG in future versions).
Alas, I don't have Illustrator so I used ViewerSvg, a free SVG viewer and XAML exporter (see Figure 4).
The XAML output produced by ViewerSvg is a good start, but it can't be used directly with Silverlight namespaces, so you need to do some manual tweaking. Adding the code in Listing 1 within the Canvas object will give your stopwatch the second hand.
Note that by default Silverlight renders objects in the order they appear in the XAML source. You can change this by setting the Canvas.Zindex attribute.
The minute hand is similar to the seconds hand, but it's smaller and positioned differently. To scale it down, use the Canvas.RenderTransform node as shown in Listing 2.
Implementing the Animation
Now you have all the components of the stopwatch UI ready and it's time to make it work. The last change you should make to Page.xaml is adding a timer component that uses the storyboard DoubleAnimation element as a timer and sets a duration to the tick time:
<DoubleAnimation Duration="00:00:0.02" />
Now open Page.xaml.cs and add the following variable declarations just before the Page_Loaded method:
private DateTime _startTime = DateTime.Now;
private TimeSpan _stopTime = new TimeSpan(0);
private bool _is_running = true;
In these declarations, _startTime holds the time when stopwatch started, _stopTime holds the interval measured, and _is_running is the boolean flag indicating whether the stopwatch is running at the moment (see Listing 3).
Within the Page_Loaded handler after InitializeComponent(), assign an event handler to the timer's Completed event:
timer.Completed += new EventHandler(_Tick);
The _Tick method will handle the Completed timer event, after which the timer starts (and you will need to restart it inside the _Tick code). See Listing 4.
Note that although you didn't explicitly declare a timer variable you can use it in your code. Silverlight automatically defines the variables with a x:Name attribute for all objects in your XAML.
Finally, add the event handler code, which will display the time elapsed:
void _Tick(object sender, EventArgs e)
DateTime now = DateTime.Now;
TimeSpan dt = ((TimeSpan)(now.Subtract(_startTime)));
dt.Hours, dt.Minutes, dt.Seconds, dt.Milliseconds / 10);
RotateTransform sRotate = new RotateTransform();
sRotate.Angle = (dt.Seconds + dt.Milliseconds * 0.001) * 6;
secHand.RenderTransform = sRotate;
RotateTransform mRotate = new RotateTransform();
mRotate.Angle = (dt.Minutes + dt.Seconds * 1.0 / 60.0) * 30;
minHand.RenderTransform = mRotate;
// restart the timer
Using the .NET classes DateTime, TimeSpan, and String makes it very easy to format and display the time interval. (You have to restart the timer within the handler to keep it running.)
Press F5 and you will see your stopwatch working! Thanks to the power of .NET it took only a few lines of code.
Your stopwatch works but it still has two buttons that don't do anything. That's easy to fix. Assign the event handlers by adding this code to Page_Loaded method:
If you actually type this code, Visual Studio allows you to complete the line and then automatically creates the handler stub once you enter "+=".
Making the Start/Stop button work requires saving the interval elapsed from the moment the device is stopped to when the count is resumed and subtracting that from the current time:
void btnStartStop_MouseLeftButtonDown(object sender, MouseEventArgs e)
_is_running = !_is_running;
DateTime now = DateTime.Now;
_startTime = (DateTime)(now.Subtract(_stopTime));
DateTime now = DateTime.Now;
_stopTime = ((TimeSpan)(now.Subtract(_startTime)));
void btnClear_MouseLeftButtonDown(object sender, MouseEventArgs e)
_stopTime = new TimeSpan(0);
_startTime = DateTime.Now;
Deploying Silverlight applications is easy. You upload the HTML page and all its resources along with a Silverlight assembly DLL to a web server. All the code executes on the client side so there are no special system requirements for the server. To deploy the stopwatch application, upload the following files:
You can check out a live example here.
A Great Browser-Based Rich Media Platform
Leveraging old (.NET) and new (Microsoft Expression Design, Microsoft Expression Blend), Microsoft offers a great platform for browser-based rich media applications. The programming experience is very intuitive and will be particularly familiar to any developer who has worked with the .NET platform before. Plus Microsoft provides all the necessary tools to separate UI design from implementation.
Silverlight's XAML-based declarative UI markup, which loads at run time, offers a high level of flexibility. When combined with high-performance .NET code, it becomes a serious competitor to the Adobe Flash platform.
The obvious issues facing Silverlight are adoption rate and platform support. By supporting Mac OS X and Firefox in the very first alpha release, Microsoft demonstrated its willingness to have Silverlight run on different operating systems and browsers.