December 3rd, 2009
Using what’s there.
Generally speaking, “rebuilding” an application is a relatively bad idea.
The first build of [rssTunes][1] had already taken me about two weeks longer than we’d estimated, and I was relatively happy with how everything had turned out. If you hadn’t looked at my code, you’d never know there were any issues with it.
But there were.
Being new to Silverlight development, I’d been approaching interface development that same way I’d approached development in Flash. After Rob and his team had completed the interface mockups, I’d break the interface down into individual controls – play button, volume slider, pause button, etc. – and import each control into Blend. The controls would be made of nothing more than a whole mess of Paths, which I’d then rebuild using things like Rectangles, Borders and a few complex Paths where necessary. I’d then start plugging away in Visual Studio, adding event handlers and timers left and right to make those basic shapes behave like whatever control they were supposed to resemble.
Consider the duration bar in rssTunes.
Beneath the artist and track name in the player, there’s a progress bar that updates to show you how much of the current track you’ve played. It’s a fantastically basic control, but I felt my first implementation was barely above amateur grade.
The duration bar was built using three Rectangles, one layered atop the other. The bottom most was stretched across the entire width of the player, and then I had a second one that started off with a width of 0. Every second, I’d check to see how much of the track the user had played – since he could of paused the track – and manually calculate how wide the second rectangle needed to grow to reflect that.
I’d written over 200 lines of code to create nothing more complicated than a progress bar! Worse, it didn’t even support every state we really needed in the application. When a track was buffering for instance, the progress bar should really have switched to an indeterminate state, to reflect that I didn’t know how long was left in the track. But doing that would have required another 100 lines or so, and I was already behind schedule.
Now, there’s nothing wrong with doing things that way. It’s how you have to build custom looking controls in just about every application environment under the sun. Basic shapes, lots of code. It’s just how its done.
But it was a massive waste of time in Silverlight.
Part of my attraction to Silverlight and is how it handles interface controls. Out of the box, Silverlight includes fully-wired interface elements of just about every kind; buttons, progress bars, tab controls, tree views – you name it. This lets you get a working interface up and going quickly.
But Silverlight was also built with the understanding that you’d probably want to customize the way those controls looked. Instead of having to jump through the usual hoops – creating a subclass of the control programmatically and overriding all of the drawing routines – you can customize the look of the control without writing a single line of behavioral code.
Silverlight uses a concept called “templates” to separate behavior from appearance. Every control has a template; a collection of shapes and other controls that make it up and form its “visual tree”. In the case of a progress bar, there’s a set of rectangles just like I’d built on my own. But the template also includes things like states and transitions.
Behind the scenes, Microsoft’s already written all the behavioral code to make the progress bar grow, disable itself and to display an indeterminate state. All we have to do is override the control template, and make whatever changes to the appearance we want. We don’t have to worry about the wiring.
Blend makes this really easy.
In Blend, you can edit these templates visually. You just click on the control you want to edit and select “Edit Template” from the menu bar. You’ll get a list of all the states that control has, and you can go through each state and edit it to your hearts content.
When we started the rebuild, I decided to do this for all of our controls. Instead of building up every single aspect of the UI from scratch, and then wiring up each control with a bunch of MouseDown, MouseUp and Timer events, I just created a handful of custom control templates – one for each type of control we needed.
The resulting project, which is up on CodePlex for your review, is massively simpler both in the XAML and in the C# code that drives it. The code no longer reads as a bunch of shape manipulations. Reading the code, you can tell I’m working with specific types of controls, and there’s way less code devoted to interface junk.
Best of all, I get tons of behavior for free. The buttons in the first version of rssTunes were really just static images. You clicked on them, but very few behaved as you’d expect. There were no roll-over states on buttons, or click states. Now, every single interface control has the full range of states.
I didn’t have to write a single line of code to do it.
[1]:http://www.rsstunes.com
