Creating a Quick and Dirty App in Silverlight
There comes a point, usually within 3-6 months after I commit to a new technology, when it becomes my platform of choice for throwing together quick applications… when I just find it easier to think in terms of the new technology than one of the old.
I also find that it usually comes in two stages: first, it is easier to use the new technology for small illustrative programs, then it is easier for creating quick and dirty utilities, apps, whatever it is I need to get done.
Today I had my first such opportunity when my daughter needed a stop watch for her Mac. Rather than looking for one (I'm sure there are hundreds) it just seemed easier to throw it together using Silverlight.
Total development time, including thinking, napkin design, layout in Blend, coding, debugging, and testing on Windows and Mac… 20 minutes. Not too bad.
One of the things I enjoyed about this project was that it reminded me how very cross-platform Silverlight really is. This was, of course, written and tested on Vista, and yet, when I ran it on the Mac, it looked just like a Mac program should look. I had to go back and run it on Vista to remind myself that it started out life looking like a Vista program!
That was kind of neat.
Start In Expression
Creating the program itself was painfully simple. I started out in Blend, and created a grid, then filled in the heading with a Textblock, added a row with three buttons, then four more text blocks.
Once you get over the idea that Blend "really isn't for our kind" – it is a gas. I make a point of using Comic Sans MS as I'm told it is a clear signal to any designer that I don't have a clue what I'm doing design-wise; it's the design equivalent of wearing a button that says "what is an object, anyway?"
…Proceed To Visual Studio
With the UI in place, and all the little UI objects named, I flipped over to Visual Studio to write the code to support the timer.
I won't walk you through every detail (unless you need the sleep) but briefly… I gave each button its own event handler (I'd probably consolidate this to a single handler if the program were any larger). Taking them easy to harder…
The Pause button calls Pause( true) which disables the Pause button (so you can't press it twice), and sets a paused flag.
The Stop button disables both the pause and the stop button and sets the started flag to false and turns off the timer (timer is explained in just a moment). The net effect is to stop everything but leave the current elapsed time showing.
The start button has all the fun. It enables the Pause button and sets the startTime member variable to now (we keep track of two times, the time since the start button was first pressed, and the time since it was most recently pressed). It then calls a helper method named Start.
The helper method checks to see if this is the first time the start button has been pressed. If so it records the time (we use this for the total elapsed time) and enables the stop button and we reset the elapsed time and start up the timer.
The timer uses a System.Windows.ThreadingDispatcherTimer as explained here.
The start code (combined and cut down) looks like this:
1: void startButton_Click( object sender, RoutedEventArgs e )
3: // un-pause
4: Pause( false );
5: // start a new elapsed time
6: startTime = DateTime.Now;
10: private void Start()
12: // if first time started
13: if ( started == false )
15: started = true;
16: stopButton.IsEnabled = true;
17: firstStartTime = startTime;
23: public void StartTimer()
25: // set up timer with event handler
26: timer = new System.Windows.Threading.DispatcherTimer();
27: timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
28: timer.Tick += new EventHandler(TickTock);
33: // event handler for timer (10 times/second)
34: public void TickTock( object o, EventArgs sender )
36: if ( !started )
39: totalElapsed = DateTime.Now - firstStartTime;
40: TimeSpan elapsed = notPausedElapsed;
42: if ( !paused )
44: TimeSpan temp = DateTime.Now - startTime;
45: elapsed += temp;
48: // display paused and total time
49: time.Text = elapsed.Hours.ToString() + ":" + elapsed.Minutes.ToString() + ":" + elapsed.Seconds.ToString();
50: totalTime.Text = totalElapsed.Hours.ToString() + ":" + totalElapsed.Minutes.ToString() + ":" + totalElapsed.Seconds.ToString();
As you can see, no rocket-science; and very familiar; we've all done it a zillion times. But it works, and it works on the client, cross-browser and cross-platform. You can stream it or you can just drop the .xap and html file right on the machine so you don't have to be on line to use it. Sweet.
Here's the source code for this post: RachelTimer1.zip