The form that collects data has two parts. The first part collects data from the user and from device peripherals (the photo and GPS data). The second sends the collected data to the server.
To collect the Title and Description for each record, the application just needs a couple of TextBoxes (see Figure 2
). Users can enter required values, and the application can read the entered values from the TextBox.Text
property—in other words, the code is identical to standard .NET applications. Obtaining the date and time is also standard; you can get the current date and time using the DateTime.Now
|Figure 2. Adding a New Record: To create a new record, users enter a title and description, and then click Send.|
Getting a GPS position is slightly more difficult; you need to access the GPS receiver, read data, and then parse it to obtain latitude and longitude values. This could be a complicated process, but fortunately, Windows Mobile provides a GPS API that makes it easy. You can call the API from managed code just as you would any other unmanaged API. If you aren't familiar with calling unmanaged code, there's some good news: the Windows Mobile SDK download includes a full working example showing the code required to access the GPS API and retrieve the devices's current position. You need only subscribe to an event, and you get the data, ready to use.
The example application uses the project provided with the Windows Mobile 6 SDK, but version 5 has the same code. Using this approach, you only need to configure the GPS API on the device to connect it to a GPS serial port (for example, the virtual serial port defined with a Bluetooth connection). You can get the current position with this code:
' -- reads the position from GPS
Dim gps As Microsoft.WindowsMobile.Samples.Location.Gps
' -- opens GPS device connected to GPS API
gps = New Microsoft.WindowsMobile.Samples.Location.Gps
Dim pos As Microsoft.WindowsMobile.Samples.Location.GpsPosition = _
newItem.Latitude = pos.Latitude
newItem.Longitude = pos.Longitude
Catch ex As Exception
' -- position is unavailable
If gps IsNot Nothing AndAlso gps.Opened Then gps.Close()
In this example, if GPS data is unavailable (for example, the GPS device is off, or there is some configuration error), the code just ignores the problem and doesn't provide a position in its record. However, in real-world applications in which position is critical, you may need to handle this scenario better, for example, require the user to turn on the GPS functionality, or reboot the device.
Taking a photo is a more complex operation. But again, the Windows Mobile SDK includes a managed object that can do most of the work, the Microsoft.WindowsMobile.Forms.SelectPictureDialog. The dialog provides all the UI and background code for taking a photo and saving it in a file, or for selecting an existing image file on the device's memory. So your application just needs to wrap this to display the dialog and read any saved files. Those files hold the photos needed for the sample application. Note that there are other ways to take a photo programmatically that range from calling the device's API directly to creating a custom dialog that doesn't save any file but would simply take a photo and manage it in memory (this is probably the best solution, and certainly the most flexible). However, for this application a simple solution will suffice, so it uses the ready-made SelectPictureDialog
You can also check if the device has a camera by calling the Microsoft.WindowsMobile.Status.SystemState.CameraPresent
method, which you can access by referencing the Microsoft.WindowsMobile.Status assembly. The required code is quite simple: you show the dialog, and then read from memory the file that the dialog has selected (which, in fact, is the photo taken with the camera and saved to disk by the dialog itself).
If Microsoft.WindowsMobile.Status.SystemState.CameraPresent Then
Using selectPictureDialog As _
Microsoft.WindowsMobile.Forms.SelectPictureDialog = _
selectPictureDialog.Title = "Travelogue example"
selectPictureDialog.CameraAccess = True
If DialogResult.OK = selectPictureDialog.ShowDialog() Then
' -- reads image from file
Dim image() As Byte
Using stream As System.IO.FileStream = _
ReDim image(CInt(stream.Length) - 1)
stream.Read(image, 0, image.Length)
' -- assigns image to item to upload
newItem.Image = image
|Author's Note: Running the code to take a photo targeted to Windows Mobile 5.0 requires that you test your application on a real device that has a camera. Device emulators cannot provide a virtual camera, so they will present just a form to select an existing image file from your memory. Windows Mobile Standard 6.0 emulator can provide a better experience by emulating camera controls, but clearly it cannot provide real camera emulation.
After collecting all the data, you need to send the record to the remote server for permanent storage. Visual Studio and the .NET framework provide robust web service integration, so calling a remote function and passing data is quite trivial. All the heavy work gets delegated to .NET libraries.
Here's the required code:
Dim assignedID As Guid
' -- prepares data to send
Dim newItem As New Travelogue.Travelogue
' -- [omitted: assigns value to newItem's properties:
' Title, Description, Latitude, Longitude, Image, etc.]
' -- calls the remote web service to upload new record
Dim assignedID As Guid
Dim remote As New Travelogue.TravelogueService
assignedID = remote.LoadData(newItem)
' -- reports operation has completed
MessageBox.Show("Data uploaded succesful with ID " & _
assignedID.ToString, "Operation Complete", MessageBoxButtons.OK, _
' -- closes current form and releases resource
Catch ex As Exception
MessageBox.Show("Unexpected error during upload." & vbCrLf & _
ex.Message, "Error", _
|Figure 3. Sucessful Send: This corroborating message appears after a user successfully submits a new record.|
As the preceding code shows, all you need to do is create an instance of the WS proxy that Visual Studio creates for you when you add a web reference to an existing web service. Then you can simply call the remote method as if it were a standard, local object. The preceding code displays any return message (see Figure 3
) or error message if the operation fails. Note that you cannot distinguish the remote call from a standard call.