Introducing BabySmash - A WPF Experiment
WPF (Windows Presentation Foundation) is confusing, to me at least. It's one of those things that is so completely different from how things were done in the past that it's not only hard to just pick up, but it's hard to tell what's the right way to do things. Often, there's a half-dozen ways to do something but no way to know which is the right. By right, I mean, most robust, most reliable, most future-proof, most supported, most compatible. It's powerful, but the power isn't immediately discoverable.
A Little Personal History
I'm a Win32 guy from way back. To be honest, I'm a Win16 guy. I cut my teeth when Hello World was 92 lines of C code on Windows 3.0, not counting the dialog resources. I worked on internationalizing applications in '95 when thunking (translating between 16 and 32-bit) was all the rage. We had an educational security application that needed to run in DOS, Windows 3.1 and Windows 95, and they wanted to re-use as much code as possible, so I #ifdef'd my way to glory.
I not only understand Win32, but I understand it's historical context and many of the design decisions behind it. Certainly not as much as Raymond Chen, but I devoured Petzold's legendary book, as did we all, and when MFC came out, I understand exactly what it abstracted and what it didn't.
WinForms is a managed layer over Win32 Windowing, and not only does Win32 sneak out occasionally in your code, but so does (of course) many other Win32 APIs.
OK, fast forward to this past weekend. My 2.5 year old and 6 month olds are constantly smashing on the various computers around the house. There's two Macs and four PCs in various locations. I've got a great free toddler-specific application called AlphaBaby installed on the Mac that makes sounds, shows letters and numbers while ostensibly protecting the machine (the software at least) from the kids. When I see my kids playing with it with such enthusiasm, I always think of the Incredible Hulk when he says "Hulk! Smash!" so this is "Baby! Smash!"
I always wanted a Windows version of AlphaBaby, and some Googling didn't find me what I wanted, although I knew it must be out there. (Of course, now many of you have shared with me your favorite toddler programs. Someone should re-write KidPix for the PC. THAT was a great application.)
My wife was watching some horrific movie on Lifetime (seriously, Patrick Swayze was in it and it wasn't Dirty Dancing) so I figured I'd spend a few hours and bang out a little application for the boys. Then I realized that this was a fine opportunity to learn WPF. I understand the general ideas behind WPF and Chris Sells has explained some aspects of it to me. Suffice it to say, WPF is a complete re-imagining of how Windows Client Developer should work - hence it's relative inaccessibility to folks like me who are deeply routed in PeekMessage. ;)
File|New WPF Application and some poking around got me some progress, but I was really trying to make the code clean. I had two goals: make it work and do it well.
Then, it hit me. "Make it work' usually is the most important goal, so I accepted that I don't know WPF and just made it work using techniques I already knew. About 6 hours later, a lot of hacking, some sample wav files of kids laughing, a quick web search for free "Web 2.0 templates," register a domain, upload, and I had http://www.babysmash.com and a workable ClickOnce WPF application that's about 60% of where I want it.
Here's some of the "features." Note that some of these are technical features. Some are kind of obscure, but as a whole, I think these represent a good representative mix of the kinds of things that Windows Client Programmers might find themselves trying to figure out. I think it's a decent sample because it's complex without being oppressively so, it's easy to get one's head around the requirements, it has a lot of possibilities, and it touches all over the platform (BCL, WinForms, Win32, WPF).
- Silly Graphics
- Options Dialog and Settings saved in Isolated Storage
- Keyboard Hooks - Disabled Windows Key, ALT-TAB, Ctrl-Esc
- ClickOnce (is it viable? sure makes auto-updating easy)
- Kiosk Mode (Full Screen)
- Multi-monitor Support (almost)
- Multimedia, Playing audio files
- Text to Speech
Future Features Ideas
- 3D? Animations? Gradients?
- Code Signing Certificate to avoid warning
- Mouse drag/painting support
- Better/more Multimonitor options
- Simultaneously add shapes on n monitors
- Optional install as Screensaver?
- When .NET 3.5 is released, support the smaller .NET 3.5 Client Install
- Add custom WAV files (my voice?) for letters/shapes, rather than TTS
- Maybe let parents record their own voices
- Does it work on non-English Keyboards/Systems?
- Does it make sense/is it useful with non-Latin languages? Chinese, Arabic?
- Logging/phone-home when exceptions happen
- About Box (woohoo!)
Did I mention the code sucks deeply?
it also has some "hidden features." By hidden features, I mean, the code sucks. Deeply. Which is kind of the whole point. After I abandoned my "do it well" goal and focused on "make it work," I made ridiculous progress. Of course, I'm not sure the fate of my immortal soul after writing this code, but calling back to last week's post on how none of us really knows what we're doing, why not use this as a learning experience?
I decided to not only hack this together, but also to consciously not do a refactoring pass. This is the code exactly and horribly as written the first time, comments, dead code, duplicated blocks, and random copy-pastes from
the bathroom wall of code CodeProject and MSDN. Don't judge me too harshly because you KNOW you've written this kind of crap yourself, Dear Reader. The kind of code that makes you need a shower later, but it works and it solved the problem.
Problems as I see them
The code is on CodePlex, and this is my own stream-of-consciousness review of the code and functionality.
- No real design
- No separations of concerns between objects
- Utils class (isn't there always a Utils class?) is schizophrenic
- Unclear to me how to convert the low level Win32 calls to WPF-eese.
- I think there's easier way to have "stroked" (outined) characters.
- Not modular - no way to add new shapes and have sounds associated with them.
- ConfigurationManager/IsolatedStorage - feels like I shouldn't have had to do that.
- Audio - used Win32 APIs. Do the WPF managed API have the same perf?
- If you slam on the keyboard too fast, like wipe your hand over it, it can crash in un-managed code. Is this the global keyboard hook gone wrong or something more sinister?
- Need to capture Alt-Space
- Relationship between Main Window, Options, and configuration details is shaky at best. There should be a pattern for chunks of config state that might change during the process.
- The random letter/shape positioning has some hard-coded fudge factors that feel gross.
- No tests - how would you test something like this?
- No thought to threading issues (do I have any?)
- Multimonitor is cheesy, and the Windows on other monitors don't update unless they have focus. How can dispatch (Replay/Tivo?) keystrokes/events too n windows at once so they all update?
- Multimonitor - I'd like to detect on window being closed, then close them all.
- Splash screen?
- No tracing, debugging, exception handling, logging.
- I keep calling into System.Windows.Forms. Are there known WPF limitations on keyboard handling?
- If you hit enough keys fast enough, you have to wait for the "queue" to empty. Can I solve that and drop keys if something fills to fast? My own key queue?
- Not localized - magic strings.
- I'm not really using XAML. Is there a better, more declarative way to do some of this?
I'd like to try two things here. First, what I'd like to do is have a group code review. Leave your thoughts in the CodePlex Issue Tracker and code in <pre> tags. Be sure to read them first so you aren't duplicating effort. Of course, even better, feel free to blog your improvements and diffs or email me diff files (firstname at lastname.com).
Second, I'm going to hunt down WPF programmers. Not just Microsoft Employees, although I'll go find the WPF team and ask them, but I want to talk people who have succeeded and failed at WPF applications and get their ideas on refactorings, structure, design, and correctness. Help me (us) understand how it works and if it's better.
Then (hopefully) over a series of blog posts and maybe a podcast or two, we'll have two applications, before and after, that we can look at. One will be my initial hacked-together-but-functional application, and one will be a completely refactored, group-vetted, expert-reviewed sample that represents (theoretically) a well-written WPF application. The app will implement all the features above and more, and each "feature" will be a little best-practice that someone can use in their app. This way we'll have not just a random sample - with credit to Rob Conery's MVC Storefront application and his transparent design process - but two, before and after, and at some point I'm hoping my brain will break out of my Win32 thinking and I'll better understand WPF idioms.
I will tag the posts on my blog in the BabySmash category. I'll also be trying some other mostly unrelated experiments, as I'll use Git for local, offline source control, but I'll be pushing my major commits from Git to TFS (Team Foundation Server) at CodePlex as well as using TFS for issue tracking.
Have at it, the source is up on CodePlex, you can download a ZIP.
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
And for the record my boy loves it, he didn't want to stop.
The code might be ugly and not the way you'd design it if you knew the system inside and out but it's a learning process and with the great refactoring tools available in VS you can mash it into shape much easier than before :)
This sounds like a lot of fun and I for one am going to do my best to follow along. I hope to learn enough to possibly contribute.
In a slightly unrelated fashion I have a somewhat related question.
Is there the pontential here to have something worth using as an example when pointing out to pointy haired people that just because we "made it work" doesn't mean it is correct? Taking into consideration the "real world" maybe we can gather enough information to be able to give reasonable arguments for actually fixing things. Remember that if this was most "enterprise" shops this app would pretty much be v1.0 . Making changes to code that was already written that didn't fix a "show stopper" would be looked down upon and questioned.
I know that sounds kinda off the wall but this is a great chance for those of us who don't have the privelege of working in environments where our peers and administrators understand our concerns. We have to explain needs like what is needed here to people who might not understand what it means to honestly feel like you need to take a shower after writing "make it work" code .... even if it does "work"... for now.
These kinds of interactions I think are just as important to software development as learning any number of languages/ API's/ patterns etc. We need to learn to be able to explain why we learned something and why doing it better is a good idea. For my self at least I know this is something I have never been able to master.
ok... I'll go stop ranting now...
Having used WPF for a while now, it's interesting to see someone who is obviously an experienced developer use it for the first time. The Options window is especially telling. I think that shows the weakness of the visual designer making use of XAML. I've found the only way to take advantage of WPF's awesomeness is to write the XAML yourself.
Very good idea for learning the WPF paradigm too!
You should checkout Poisson Rouge. Their games are pretty interesting. Well, my four-year-old loves it anyway, and they look more interesting than the Playhouse Disney offerings.
"Grabbed the code, set a breakpoint, hit F5 and then... oh hang on, how do i get to my IDE to see the breakpoint with all these keyboard hooks & 'stay on top' maximised chromless windows ;-) "
Sherwin, you could try remote debugging until Scott or others try to add that support (i.e., if running Debug mode, allow ALT+TAB, chrome, etc...)
And yes, I HAVE written code like that.
Line 23: MainWindow.WindowState = WindowState.Maximized; //Do it here, rather than in XAML otherwise multimon won't work.
Then you can run it as a regular app and debug fine. Sorry.
For those that are interested, here is a large list of WPF blogs: Blog List
What's up? Am I the only one?
Using FireFox 2.0 on Vista 32bit
So did I post that in the wrong place, or is there some way to use HTML in the CodePlex issue tracker that's off by default?
Ian - Looks like I was wrong about the Issue tracker supporting pre blocks. Maybe just attach a file?
Thanks for sharing this app. My son will love this :-)
My wife is teacher in the Bellevue, WA school district. She has KidPix installed on the Dell PCs in her classroom and on her Dell XP laptop.
You can download it from http://www.littlecamelot.com
Alt-F4 didn't properly exit the prg; instead it reduced the prg to only monitor1. Monitor2 showed normal prgs running and allowed me to do stuff there.
Ctrl-Alt-Shift-O seemed to launch the options menu but it remained hidden behind monitor1's white screen and inaccessible.
Ultimately, I was only able to terminate the prg via task mgr.
Next time i'll try to replace laughter wav files with non-human sounds.
Hopefully another father-programmer will join forces with me.
Oh, and by the way! He left message to you here; “HHHHHGGR6JJEKKDDDDEDASEW”. Not quite sure what it means yet, but I’ll guess BabySmash 2.0 will have a Translate-to-grown-up-readable-format button somewhere?
Keep up the good work :)
Comments are closed.
Wow, the hits keep on rollin'.