n a previous article, I discussed developing mobile applications using the Microsoft Mobile Internet Toolkit (now renamed “ASP.NET Mobile Controls”). Microsoft designed the ASP.NET Mobile Controls to help developers build applications that run on devices with limited processing power, such as mobile phones, where much of the application logic resides on back-end Web servers.
In contrast, the .NET Compact Framework (.NET CF) is a scaled-down version of the .NET Framework, which you use to build applications that run on specific mobile devices with sufficient processing power. .NET CF supports only devices running Microsoft operating systems?specifically, Windows CE 3.0 (used in Pocket PC 2000 and Pocket PC 2002 platforms) and Windows CE.NET. The idea behind .NET CF is that it provides a familiar environment for desktop developers to build applications for mobile devices. This article shows you how to use Visual Studio to develop mobile applications that run on the Pocket PC.
|Figure 1. To create a new Smart Device Application project, select the appropriate template to from the New Project dialog.|
Developing a Pocket PC Application
In this article, you’ll see how to build a Pocket PC application using Microsoft Visual Studio .NET 2003 (currently in final beta, but due to be released in early 2003). The sample application described in this article is a text editor that lets users check for word definitions, spell-check words, and translate text to different languages. All these capabilities are available via live Web services.
|Figure 2. Choose the project type from the Smart Device Application Wizard.|
To get started, you first create a new Smart Device Application project using your preferred language (the sample code uses Visual Basic .NET). Figure 1 shows the New Project dialog.
Selecting the Smart Device Application template launches the Smart Device Application Wizard, which asks you to select a platform and project for the application you want to build. For this project, choose Pocket PC and Windows Application (see Figure 2).
As you can see in Figure 3, the Visual Studio environment when developing a Pocket PC application is very similar to developing a Windows application.
|Figure 3. The Visual Studio .NET interface loaded with a new .NET CF application.|
The familiar Toolbox contains the available .NET CF controls, which are a subset of the Windows Form controls. One vital fact to bear in mind when building .NET CF projects is that not all the methods and classes in the full .NET Framework are available in .NET CF. Due to the limited processing power inherent in mobile devices, the .NET CF team at Microsoft removed a large subset of the methods available in the full .NET framework. The resulting lean .NET CF framework runtime requires a mere 1.5MB footprint.
|Figure 4. Populate the Windows Form with the various controls for the sample application.|
Building the Sample Project
First, populate your Windows Form with the various controls (see Figure 4):
Next, insert the menu items shown in Figure 5 into the MainMenu1 control:
Here’s a tip: Enter a hyphen (–) for the menu separator in the Translate menu item. A bug in the final beta prevents the separator from showing correctly (in fact the program crashes when you try to run it). The workaround is to rearrange the code generated by the Windows Form Designer as shown below:
Me.MenuItem5.MenuItems.Add(Me.MenuItem12) ' --move the following line after the Add method Me.MenuItem12.Text = "-"
|Figure 5. The sample application requires these menu items.|
Moving the statement containing the “-” assignment to just after the Add() method of the MenuItems object does the trick.
Adding Web References
The sample project in this article consumes three Web services:
- Dictionary Web service?Performs a lookup for meanings of a word. http://www.xceer.com/trans/dic2.asmx
- Spell Check Web service?Checks for alternative spellings to a given word/sentence. http://ws.cdyne.com/SpellChecker/check.asmx
- Translation Web service?Translates a given sentence to a specified language. http://www.xmethods.net/sd/2001/BabelFishService.wsdl
Right-click the References item in the Solution Explorer, and then click the Add Web Reference item from the popup menu. Enter the URLs for the three Web services listed above into the URL field in the section of the Solution Explorer as shown in Figure 6.
After adding the Web References, your Solution Explorer should look like Figure 7:
|Figure 6. Use the Add Web Reference dialog to add Web service references.|
|Figure 7. Here’s how your Solution Explorer should look after adding the three Web service references.|
|Figure 8. Setting the form’s MinimizeBox property to False causes the OK button to appear.|
Setting Form Properties and Coding Event Handlers
Setting the MinimizeBox property of the Windows Form to False causes it to display the OK button ; otherwise, it displays an “X”. Clicking on the OK button closes the application, whereas the clicking the “X” minimizes the application window. When you are debugging your application, clicking on the OK button terminates the debugging process in Visual Studio .NET; but if you click the “X” button, you have to terminate the debugging process in Visual Studio .NET manually.
To summarize, the OK button terminates the application, whereas the “X” button minimizes the application. Figure 8 shows how the setting affects the final form’s title bar.
Activate the Menus
Now, you can activate the menus. But first, you must write the code for the File menu. The first menu item is the New item:
Private Sub mnuNew_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuNew.Click Dim response As Microsoft.VisualBasic.MsgBoxResult response = MsgBox("Save existing file?", _ MsgBoxStyle.OKCancel, "Save") If response = MsgBoxResult.OK Then Save() Else Return End If TextBox1.Text = "" currentFilename = "" StatusBar1.Text = "New" End Sub
When users click on the New item, the application first displays a message box asking if they want to save the file. If so, the code calls the Save() method and resets the form; otherwise, it exits.
Next, the Open item prompts users to enter a filename using the OpenFileDialog class. It then opens the selected file using the StreamReader class and displays the text in the TextBox control:
Private Sub mnuOpen_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuOpen.Click Dim openFileDialog1 As New OpenFileDialog Dim sr As StreamReader openFileDialog1.InitialDirectory = "c:" openFileDialog1.Filter = "txt files (*.txt)|*.txt" If openFileDialog1.ShowDialog() = _ DialogResult.OK Then currentFilename = openFileDialog1.FileName StatusBar1.Text = currentFilename sr = New StreamReader( _ openFileDialog1.FileName, _ System.Text.Encoding.ASCII) TextBox1.Text = sr.ReadToEnd() sr.Close() End If End Sub
Similarly, the Save menu item calls the Save() method:
Private Sub mnuSave_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuSave.Click Save() End Sub
And the Save As? menu item calls the SaveAs() method:
Private Sub mnuSaveAs_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuSaveAs.Click SaveAs() End Sub
The SaveAs() method implementation uses the StreamWriter class to save the text in the TextBox control to a file. It prompts the user to enter a filename using the SaveFileDialog class:
Public Sub SaveAs() Dim saveFileDialog1 As New SaveFileDialog Dim sw As StreamWriter saveFileDialog1.InitialDirectory = "" saveFileDialog1.Filter = "txt files (*.txt)|*.txt" If saveFileDialog1.ShowDialog() = _ DialogResult.OK Then currentFilename = saveFileDialog1.FileName StatusBar1.Text = currentFilename sw = New StreamWriter( _ saveFileDialog1.FileName, True, _ System.Text.Encoding.ASCII) sw.WriteLine(TextBox1.Text) sw.Close() End If End Sub
After saving a file, the application remembers the current filename using the global variable currentFilename.
The Save() method capitalizes on the saved file name by first checking to see if the currentFilename variable contains a filename. If not, the text has not been saved previously, and the code calls the SaveAs() method. If the currentFilename variable contains a filename but the file does not exist (perhaps the user has deleted it), the code also invokes the SaveAs() method. It then saves the file using the StreamWriter class:
Public Sub Save() '---if no filename, invoke SaveAs() If currentFilename = "" Then SaveAs() Return End If '---if have filename, but file may not be there... If (Not File.Exists(currentFilename)) Then SaveAs() Return End If Dim sw As StreamWriter sw = New StreamWriter(currentFilename, False, _ System.Text.Encoding.ASCII) sw.WriteLine(TextBox1.Text) sw.Close() End Sub
|Figure 9. To check spelling, users first highlight a word and then select the Check Spelling menu item.|
Setting Up the Web Services
After creating the basic menu item functionality, you can set up the code to consume the Web services. When the user highlights a word from the TextBox control and clicks the Check Spelling menu item, the application invokes the CheckSpelling() method (see Figure 9):
Private Sub mnuSpelling_Click_1(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuSpelling.Click CheckSpelling(TextBox1.SelectedText.ToString) End Sub
The CheckSpelling() method calls the Spell Check Web service’s CheckTextBody() method and expects a return result of type DocumentSummary. It then examines the result and displays the suggested spellings using a Context menu. Each menu item in the context menu has an event handler named menuItem_Click.
|Figure 10. Users can replace selected words with the suggested spelling returned by the Web service.|
Public Sub CheckSpelling(ByVal str As String) Dim result As SpellCheckerWS.DocumentSummary Dim ws As New SpellCheckerWS.check Dim i As Integer result = ws.CheckTextBody(str, 0) If result.MisspelledWordCount = 0 Then Return End If cMenu.MenuItems.Clear() For i = 0 To _ result.MisspelledWord(0).SuggestionCount - 1 Dim mItem As MenuItem = New MenuItem mItem.Text = result.MisspelledWord(0). _ Suggestions(i).ToString cMenu.MenuItems.Add(mItem) AddHandler mItem.Click, AddressOf menuItem_Click Next cMenu.Show(TextBox1, New Point(0, 0)) 'TextBox1.MousePosition) End Sub
When users click an item on the context menu, the menuItem_Click event handler code replaces the highlighted word in the TextBox control with the text of the context menu item (see Figure 10):
Protected Sub menuItem_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) TextBox1.SelectedText = CType(sender, MenuItem).Text() End Sub
|Author Note: An easy way to examine the return type of a Web service is to set a Breakpoint after the Web service has returned a result. Figure 11 shows an active breakpoint in the Visual Studio code editor.|
|Figure 11. A breakpoint during execution in Visual Studio.|
After the Web service returns the result, you can examine the structure of the return data type using the Debug->Quick Watch? item in Visual Studio (see Figure 12):
Consuming the Dictionary Web service is similar. Selecting the Check Meaning menu calls the CheckMeaning() method:
Private Sub mnuMeaning_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuMeaning.Click CheckMeaning(TextBox1.SelectedText.ToString) End Sub
The Dictionary Web service returns a MyResult type. The MyResult class encapsulates the returned word meanings, both single and multiple. The code in the CheckMeaning() method parses and displays the meanings in a message box (see Figure 13):
|Figure 12. Use the debugger to examine the result returned by a Web service method call.|
Public Function CheckMeaning(ByVal word As String) _ As String Dim ws As New DictionaryWS.dic2 Dim result As DictionaryWS.MyResult result = ws.GetEEMeaning(word) Dim i As Integer Dim resultStr As String resultStr = result.Trans(0).ToString & " :" For i = 1 To result.Trans.Length - 1 resultStr += result.Trans(i).ToString & "; " Next If result.Trans.Length = 1 Then _ resultStr += "
" MsgBox(resultStr, MsgBoxStyle.Information, _ "Meaning for " & word) End Function
|Figure 13. Selecting the Check Meaning menu item looks up the selected word and then displays the meaning in a message box.|
Finally, the Translation Web service provides four possible translation modes, which users select from the Translation submenu (see Figure 14).
The single TranslationMenu_Click() event handles the click events for all four submenu items:
Private Sub TranslationMenu_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnuEnFr.Click, mnuDeEn.Click, _ mnuEnDe.Click, mnuFrEn.Click Dim mode As String Select Case CType(sender, MenuItem).Text Case "English -> French" : mode = "en_fr" Case "English -> German" : mode = "en_de" Case "French -> English" : mode = "fr_en" Case "German -> English" : mode = "de_en" End Select Translate(TextBox1.SelectedText.ToString, mode) End Sub
The Translate() method sends the message to be translated and the language mode, and expects a return string representing the translated sentence, which it displays in a message box (see Figure 15):
|Figure 14. The application supports four different translation modes.|
Public Function Translate(ByVal str As String, _ ByVal lang As String) As String Dim ws As New TranslationWS.BabelFishService Dim result As String Try result = ws.BabelFish(lang, str) MsgBox(str & vbCrLf & vbCrLf & result, _ MsgBoxStyle.Information, _ "Translated Sentence") Catch e As Exception MsgBox("Sentence cannot be translated", _ MsgBoxStyle.Critical, "Error") End Try End Function
|Figure 15. When a user selects one of the four translation modes, the application calls the Translation Web service and displays the result in a message box.|
|Figure 16. Select the built-in emulator for a fast, convenient way to test your application.|
Testing the Application
You can test your application in two ways: using an emulator, or using a real device. It’s faster to test using the built-in Pocket PC 2002 emulator (see Figure 16); however, despite the speed and convenience of testing on the emulator, you should test your application on a real device before you deploy it. To do that, connect your Pocket PC device to your computer via ActiveSync. Testing on real devices can reveal usability problems that you cannot easily anticipate using emulators alone.
|Figure 17. Copying the .NET Compact Framework to the emulator|
When you use the emulator for the first time (or after a hard reset), Visual Studio .NET copies the .NET Compact Framework to the emulator (see Figure 17).
To sum up, developing Pocket PC applications using the .NET CF is quite similar to developing a desktop application. In fact, that’s the strength of the .NET CF?developers can leverage their existing skill sets and achieve quick success programming for mobile devices.