Microsoft Visual Studio 2008 includes a lot of useful features for mobile developers, especially those of the database persuasion. On the one hand, you have the latest and greatest version 3 emulators, Windows Mobile 5 libraries and project templates pre-installed, and unit testing for mobile. (See the Windows Mobile Team Blog for an overview.) On the other hand, you have LINQ, a new syntax for working directly with datasets. But what is the sound of two hands clapping without touching? That's right—silence.
Here's the scoop on LINQ for mobile: technically, LINQ works with .NET Compact Framework 3.5, though with limitations. According to MSDN you get standard query operators, LINQ to DataSet, and LINQ to XML. However, the more useful LINQ to SQL designer is not supported in SQL Server Compact Edition 3.5 (see this thread). Nor will you find any LINQ objects available in your mobile project, despite having a System.Linq reference added by default. In fact, I can find neither details nor code samples regarding LINQ for Mobile on the Internet. Nor can I get any additional information from the fine folks at Microsoft. (If you find something, please let us know so we can post it here.)
The net result: while a demo of new LINQ syntax for mobile apps will have to wait, Visual Studio 2008 has a lot to offer anyway, particular with IDE tools for SQL Server Compact Edition and .NET Compact Framework. To give you some ideas of what you can do, this walkthrough will take you through the process of building a Hangman-style game called "W80 Words", aka "Weighty Words." It uses a SQL Server Compact Edition 3.5 database, albeit very rudimentary, and runs on .NET Compact Framework 3.5. For this demo, I've eschewed use of the Windows Mobile 6 emulators since they aren't included in Visual Studio 2008, opting instead to focus only on what's available without additional installs, namely Windows Mobile 5.
Project Architecture
I chose W80 Words to demonstrate a few basic concepts in a fun way. The goal here is to touch on a database just enough to show how it's used, then move on. The game will pull a word at random, then create a couple of objects to handle guessing functionality. Instead of arrays or List objects, this code uses Strings and string functions, primarily .Substring().
But the first priority is to handle a consideration that should be at the forefront of every mobile application: screen dimensions and orientation. This is best handled at the design level of a new app as it informs graphics and UI choices. For example, this game will have two primary screen areas, one for input and one for the results graphics. Because the UI doesn't need to convey a lot of information, it can be smaller than full screen size. That way I can pad the edges based on available dimensions rather than scaling the images used in the game, which is also a viable but slightly more complex option.
Splitting the UI into two sections also allows me to reposition Panel objects according to orientation. In Portrait mode, the images go on top and the input on bottom. In Landscape mode, I can simply move the panels side-by-side rather than doing a wholesale redesign of the UI. By anchoring objects within the panels, they will stay fixed in the correct positions without having to programmatically reset the location of every object in the UI.
Enough jabber. Let's code.
Step One: Create Project and Basic UI
First, set up the project:
- In Visual Studio 2008, create a New Project. called "W80Words." Choose a Visual C# Smart Device project. Make sure .NET Framework 3.5 is chosen as the deployment platform—this is a new, and extraordinarily handy feature of Visual Studio 2008.
- Rename your form to frmGameMain and give it a Text value of "W80 Words". At the same time, change the Menu name to mmuW80Menu.
Next, add a few basic controls:
- You'll need two panels for the UI. Grab the Panel control from the toolbox and draw a 150 by 150 box on top and a small one on bottom of the same width and about half the height. To help with development and testing, you might want to make the panels a different color from the background so you can see it move around from the upcoming code.
- Name the top panel pnlGuesses and the bottom panel pnlWord.
- In the bottom panel, add a Label. Call it lblAnswer.
- Below lblAnswer, add a TextBox. Call it txtGuess. This is for typing in the letter to guess. Set its MaxLength to 1. Since mobile textboxes have very little formatting control, for example you can only set TextAlign to Left, not Center, you may want to play with formatting. In the sample app, I added a smaller panel to pnlWord and set it to the same color as txtGuess, which I placed within the smaller panel. Then I shrank txtGuess to approximate a centering effect.
- In the upper-right corner of pnlGuesses, add an empty label called lblGuesses. This is positioned specifically for the graphics used in this example, so move it around if you're using different graphics. A Location of 96, 20 and Size of 48, 26 seems to work well with the assets used here.
At this point, you may want to compile and run to make sure the app at least executes correctly. When you're done, stop the application from Visual Studio 2008, but leave the emulator up and running.
Step Two: Detect Size and Orientation
As mentioned in the discussion of architecture, a big consideration for mobile apps is variance in size and orientation of the device it'll be running on. This is one of the most common questions any mobile developer has. And yet clear documentation is nearly impossible to find on the subject. As it turns out, handling size and orientation is a very simple process, thanks to the SystemState class.
First, add the following .NET references to the project:
Microsoft.WindowsMobile
Microsoft.WindowsMobile.Status
Open up the form code (W80Words.cs) and add the following use statement:
using Microsoft.WindowsMobile.Status;
In the class declaration for the form, add:
SystemState Orientation;
Go to "public frmGameMain()" and replace it with the following:
public frmGameMain()
{
InitializeComponent();
Orientation = new SystemState(SystemProperty.DisplayRotation);
Orientation.Changed += Orientation_Changed;
adjustScreen();
}
This instantiates the new Orientation object, which is an instance of the system's DisplayRotation property, and assigns its Changed event, then calls a routine you're about to create. In fact, add the following method to the class:
void Orientation_Changed(object sender, ChangeEventArgs args)
{
adjustScreen();
}
And the routine that actually does the work? Here it is:
private void adjustScreen()
{
int guessTop = 0;
int wordTop = 0;
int guessLeft = 0;
int wordLeft = 0;
switch (SystemState.DisplayRotation)
{
case 90:
guessTop = (this.Size.Height - pnlGuesses.Size.Height) / 2;
wordTop = (this.Size.Height - pnlWord.Size.Height) / 2;
guessLeft = 5;
wordLeft = pnlGuesses.Size.Width + 10;
break;
default:
guessTop = 5;
wordTop = pnlGuesses.Size.Height + 10;
guessLeft = (this.Size.Width - pnlGuesses.Size.Width) / 2;
wordLeft = (this.Size.Width - pnlWord.Size.Width) / 2;
break;
}
pnlGuesses.Top = guessTop;
pnlGuesses.Left = guessLeft;
pnlWord.Top = wordTop;
pnlWord.Left = wordLeft;
}
Here's where the action takes place. DisplayRotation gives you the angle of rotation for the display: 0, 90, 180, or 270. For typical Windows Mobile devices, you only need to worry about 0 and 90, which is horizontal. The above code positions the panels, via their Top and Left coordinates, either on top of one another or side-by-side, centered in the display based on the height and width of the particular device. I also added a little padding so the panels weren't butting up next to each other.
Go ahead and compile and run again to test the orientation change. You can see this in action in the "Finished Product" video at the end of this walkthrough.