There’s No Such Thing As Too Much Euchre! (Matt Gertz)
“Oh, no!” I hear you cry, “not another blog about Euchre!”
Well, I do like the game, to be sure. But, more importantly, the Euchre scenario enables me to try out any new technologies on a reasonably complex problem (using Visual Basic, of course). It’s my way of checking out our product to make sure that it works before we ship it out to you guys.
For my app building this time around, I chose to focus my energies in two areas – WPF, and Windows Mobile. Porting my Euchre game to these platforms was challenging in several different ways, and I thought that I’d share what I’d learned with you. I won’t list out the code, most of which hasn’t changed, but you can find it at my Temple of VB site.
Porting VBEuchre to Windows Mobile
I actually hadn’t intended to do this one, actually. I mean, I’d always meant to do such a port so that I could play Euchre on my phone, but I’d kept putting it off since there were always other important things to do. Yesterday, however, I found myself sick at home and utterly bored, so I decided to tackle the port. It turned out to be easy (for the most part) – the hardest part is actually redoing the resources. But I’m getting ahead of myself…
I started out by creating a Windows Mobile application, and then adding the resources to the default form. The process of adding controls was nearly identical to creating the original game. The only differences were:
· I used PictureBoxes instead of Labels for the cards, since Labels don’t have images in the compact framework (I should have been using PictureBoxes in the original game, anyway).
· I didn’t bother with a Logo splash, the fancy graphical scoring, nor with the player names – real estate is at a premium on a smartphone.
· GroupBoxes don’t exist, so I use labels to indicate who the dealer is.
· I added a new button to launch the game, for reasons I’ll explain later.
· There are only two menu items in the strip (Restart Game and Exit).
· There is no tooltip control.
· The status area is now a label, and only shows the most recent action.
It took me about 30 minutes to set up the form. The two bid user controls were next, and were essentially identical to their desktop counterparts (though the text in them is abbreviated). I didn’t bother with a “Rules” dialog nor an “About” dialog, so that just left the options dialog. Speech isn’t easily available on a hand-held, and the player personality choices take up too much space as well, so that just left the rule variations to add into it (Stick the Dealer, SuperEuchre, Quiet Dealer, and Nine of Hearts) and the effects (Peek At Cards and Sound Effects).
I then copied the old code and resources over wholesale, and worked my way through the errors. There were darned few of them, actually. Here’s what I ran across:
· “My” support is limited in mobile applications. For some things (like My.Application.DoEvents), simply taking off the “My” is sufficient. For other things, such as playing sounds, I had to use the System.Media.SoundPlayer object directly.
· The Timer control uses “Enabled = True/False” instead of “Start/Stop”
· I ripped out or short-circuited all code relevant to tooltips, the F2 button, default buttons, and text-to-speech, since they have no meaning in this world.
· Images have no rotation methods, so I created some by hand so that cards would be oriented correctly.
· I shortened a lot of the text messages to fit into the available display space.
That was pretty much it – or so I thought. When I ran the game, everything seemed to work fine. However, “New Game” would only work once, and clicking on it again would do nothing. This is because (as I found out) events in the .NET Compact Framework do not support asynchronous events, and my game (as it existed) relied upon that functionality in order to process the “New Game” command in the middle of a game. Thus, I now use a button to start the initial game, and then “New Game” (now renamed “Restart Game”) simply sets a flag that the event loop catches to crawl back up the stack and restart, as before.
Side note: Reentrancy (essentially recursing into event or messagehandling) is dangerous, because you can easily get into a deadlock if you mess it up. DoEvents() is therefore a controversial method to use because it’s so easy to get it wrong, and many people even feel that it should be entirely ripped out of the framework. In my case, the requirement to drive the game and still allow the user to exit it makes it sort of a necessity (unless I were to implement some fairly significant threading and message handling, and that wasn’t the point of my exercise). I worked hard to make sure that I ran into no reentrancy problems when I developed the original program, but you should be very careful whenever you use it.
My total elapsed time at this point, from the start of the project, was about one hour – not bad! I still wasn’t quite done, however. My card images, although beautiful on the desktop version, looked pretty crummy when scaled down to 31 x 24 boxes, and furthermore they were wasting memory and causing time delays due to the scaling and orientation required on each showing. I had to re-write all of my cards into the proper sizes, making them much simple looking in the process so that they were legible.
After a couple of hours of tweaking those images and adding the setup project to generate the CAB, I was almost done. One final gameplay experience encouraged me to decrease the timer interval to 100ms – that seemed to pace the game better on the phone. The final result (developed using VS2008) is available on the Temple of VB site.
Porting Euchre to WPF
As easy as porting the game to Windows Mobile was, porting it to WPF was another thing entirely. WPF and WinForms are really meant for different scenarios, and therefore they require different types of coding skills. (I actually did the WPF port before the Windows Mobile port, but since the WPF one was more complicated, I saved it for last in this blog.)
I used VS2010 Beta 2 for this port, since I was interested to see if I could find any bugs in the product. I’m happy to say that I didn’t run into any major bugs – what I did run into was a lack of knowledge on my part, and so it took me quite a bit longer (a couple of weeks, in fact) to do this port.
As in the case of the Windows Mobile port, I first started by recreating the forms in a WPF Windows Application. The WPF designer is pretty easy to use (even when dropping in 53 controls!), though I ran into a few necessary changes from what I’d done in WinForms:
· I had to be careful to position cards over the group boxes rather than in them. This is because group boxes will, when invisible, hide anything inside them. (I had to go into the XAML to do this change, because my cards kept snapping into the group box.)
· The cards became Images (the moral equivalent of a WinForms PictureBox) instead of Labels, which they really have ought to have been originally anyway. Labels in WPF don’t support background images, so this change was required. (I started out using Labels in this WPF version, and then when I realized that that wouldn’t work, I shifted them to PictureBoxes simply by replacing the class info in XAML – very cool!)
· Controls in WPF have a Z-order, but you can’t change it programmatically. Therefore, it’s important to lay down the controls in the correct order, and to make sure that you make liberal use of “IsHitTestVisible = False (or True)” to avoid inadvertently covering up a control which is supposed to be active and clickable.
· Because of the Z-order issue, it’s easier to work with user controls by simply laying them down rather than creating them dynamically. However, your user controls won’t appear in your toolbox until you’ve built them once. Additionally, accessing them programmatically requires prefixing them with a namespace, something you should keep in mind.
· The tooltip control doesn’t exist and isn’t required – each control has a tooltip, which actually makes things a lot easier.
· Controls don’t have a cursor setting, so I had to set this by hand whenever state changed.
· Timer controls don’t exist, but this is not a big deal, since you can just use the System.Timers.Timer object in the code, which works essentially identically.
· Image controls do not natively support images accessed by My.Resources – they instead prefer files (URIs, actually). To dynamically set these on-the-fly, I had to stream the bitmaps into an in-memory file, and then assign them to the image. I had to do something similar for the RichText edit control on the “rules” page.
· Menus were trickier to set up, since you can’t auto-populate them with standard items. Once you get the hang of it, they essentially work like those in WinForms.
· Font sizes in WPF refer to pixels and not points, which means you’ll likely see a font appear about 30% smaller than you expected if you’re used to WinForms – just something to be aware of. (My code doesn’t correct for this yet, incidentally, so the fonts will appear a bit smal
· The windowing controls (minimize, maximize, etc) are not set individually – to have only a minimize and a close box, the window needs to have ResizeMode set to “CanMinimize,” for example.
· Other controls work as you’d expect, except that radio buttons and checkboxes have both a Checked and Unchecked event, unlike WinForms where both are handled in one event.
The game logic was, of course, identical to the WinForms version, except where I had to retool cursors, timers, and tooltips. Nevertheless, there were a few changes that had to be made to managing the controls and dialogs:
· Instead of using the speech SDK, I took advantage of the built-in speech APIs in the framework. This resulted in much more elegant code, and a smaller package as well.
· There is no equivalent to “DoEvents” in WPF. As I was unwilling to totally rewrite the project to use worker threads and coordination messages, I leveraged a trick using DispatcherFrames that I’d found on the Internet (this is attributed properly in the code sample).
· Modal dialogs cannot be reused, and since I needed to reuse the options dialog and wanted to persist state between uses, I hooked the “closing” event to cancel the Close and instead just hide the window – this necessitated a minor tweak to my “new game” logic as well to check for the state of the options dialog.
· Disabled visible controls do not grey out, which gave me the opportunity to play around with the opacity property, which was kind of fun.
· There were numerous little changes that had to be made due to slight variations in naming conventions – e.g., Enable vs. IsEnabled – and I had to make sure that the IsHitTestVisible property was used correctly as well wherever the visibility of a control changed, due to the aforementioned Z-order limitation.
· Unlike the WinForms “Visible” property, the WPF “Visibility” is not a Boolean but instead supports an enum. Furthermore, the “Visible” part of that enum maps to 0, and the “Hidden” to 1, so if you accidentally use Booleans as argument to Visibility, you’ll get things backwards. For code readability, I threw in some If() calls to disambiguate the situation.
That work got me to parity with the WinForms version, and it works great! I’m not quite finished with the port, though, and so you won’t find an installer package for this one from me yet – now that I’ve got things working, I want to add some of the WPF special effects to the game! However, I’ve posted the code on the Temple of VB site, and the solution also includes the old code so that you can more easily compare the two.
‘Til next time,