Christian Forsberg
business anyplace
March 2006
Applies to:
Windows Mobile 2003 software for Smartphones
Microsoft Visual Studio .NET 2003
Microsoft .NET Compact Framework version 1.0
Summary: Learn how to develop mobile enterprise transportation applications for Windows Mobile 2003–based Smartphones by using Visual Studio .NET, the .NET Compact Framework, and the Windows Mobile 2003 software development kit (SDK). The source code in this article implements server components, a database, and a Windows Mobile 2003–based Smartphone client. (47 printed pages)
Download Northwind_Pocket_Delivery_Transport_WM2k3_SP.msi from the Microsoft Download Center.
Contents
Introduction
Northwind Traders's Field Delivery Business Process
Application Design
Phone Connectivity
File Integration
File Upload
Notification Infrastructure
MapPoint Web Service Integration
Northwind Delivery Web Application
Northwind Pocket Delivery Application Client Walkthrough
Code Walkthrough
Conclusion
Introduction
This article continues on the following articles:
The first article describes key elements in how to develop mobile field service applications, and the second focuses more on developing these applications for Smartphones. The third and fourth articles focus on developing mobile field sales applications. The fifth and sixth articles cover the design and implementation of a mobile logistics solution. The seventh article introduces the use of mobile devices as a transportation tool, and the article has an introduction to a delivery process. It also includes a field sample application for supporting that process.
This article is about designing and developing a mobile field transportation application based on the Windows Mobile platform for Smartphones and the .NET Compact Framework. The sample solution described in this article addresses the needs of the fictitious company Northwind Traders from a transportation and delivery process point of view. From a technology point of view, the sample demonstrates the how to do the following:
- Integrate with other Smartphone applications through the file system
- Upload files to a Web server using Hypertext Transfer Protocol (HTTP)
- Push notifications to the device by using plain sockets
- Integrate with the Microsoft MapPoint Web Service
- Do simple integration with native Smartphone functionality, such as making a call, sending a text message (a Short Message Service [SMS]), sending an e-mail, and more.
Northwind Traders's Field Delivery Business Process
The customers of Northwind Traders have vending machines that sell various products from Northwind Traders. As described in the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs, Northwind Traders is not only focusing on supplying its customers with products on time, but the company also offering customers the ability to exchange products with each other. This innovative service initiative means that customers who have too many items of a certain product in stock can offer that product to other customers. Northwind Traders is not only managing this exchange of products between customers but also offering customers a delivery service that transports the products needed between those customers. Such a business process includes the following steps:
- Create a delivery and assign it to a driver.
- Notify the driver of his or her new assignments.
- Plan the routes for pick up and drop off.
- Pick up a package.
- Drop off the package.
- Capture feedback.
- Report status.
Figure 1 illustrates this business process.
.gif)
Figure 1. Delivery business process
An interesting detail in the business process is that the driver is able to capture customer feedback while picking up and dropping off the products. This feedback can be very useful when following up with customers and also when handling customer and insurance claims. For example, one can take a photograph of a damaged package before it is picked up. If that photograph is transferred to the server and made available to the back-office personnel, it can provide great value to the business. To make this happen, we need to integrate with a camera on the mobile device and also create a way of sending the photo to the server. How this can be done will be discussed in the following sections.
Assuming we have done a good job of defining the new process, the next step is to look at the design of the solution.
Application Design
The article Northwind Pocket Service: Field Service for Windows Mobile-based Pocket PCs provides a good introduction to the architectural work in a mobile solution. The article Northwind Pocket Inventory: Logistics for Windows Mobile-based Pocket PCs includes a description of the most important deliverables (artifacts) in the application design, and the design really begins with the definition of the use cases. Figure 2 shows the use cases for the sample application.
.gif)
Figure 2. Use case model
Another very important artifact to create early in the design process is the dialog (form) model and sample dialogs. Figure 3 illustrates the dialog model for the sample application.
.gif)
Figure 3. Dialog model
The dialog model gives an overview of the dialogs included in the application and also illustrates the navigation among these dialogs. The form for the list of deliveries (plan, pick up, and drop off) is used in the main menu commands Plan, Pick Up, and Drop Off. The application implements it as a single form, but the functionality changes somewhat depending on what role the form has. The same is true for the delivery (plan pick up, plan drop off, pick up, and drop off) form.
Figure 4 illustrates some sample dialogs.
.gif)
Figure 4. Sample dialogs. Click the thumbnail for a larger image.
The sample dialogs are drawn in a general drawing tool (in this case Microsoft PowerPoint), and it is recommended that someone knowledgeable in user interface (UI) design should be involved in creating dialogs like this. The early visualization of the application dialogs gives the users and other stakeholders an opportunity to understand how the application will look (and work), and changes are also very easy to make at this stage.
In the Northwind_Pocket_Delivery_Transport_WM2k3_SP.msi, you can find all of the preceding figures in a PowerPoint presentation that you can reuse when you create your own diagrams.
Phone Connectivity
Some of the features mentioned in the rest of this article are based on the assumption that the phone has a network connection. The common option in a Global System for Mobile Communications (GSM)–based network is to use General Packet Radio Services (GPRS). GPRS enables the clients to be online—not necessarily using their connection, but available on the network. As long as the clients are not using the connection, the client doesn't generate communication costs.
However, the phone is typically connected to the operator network—not the company network. This means that internal company resources (for example, servers) are not directly available, but some can be reached by using technology such as secure tunneling over the Internet, normally referred to as a virtual private networking (VPN).
To get full access to company resources, many operators offer a service that enables all devices for a company to connect to the company network and get Internet Protocol (IP) addresses on that network. The service means that the company gets their own Access Point Name (APN), and therefore the service is often referred to as Private APN. Because Private APN enables all devices to be connected to the company network, this service opens up many possibilities. For example, because the devices do not need to go through the company firewall (which is the case with typical GPRS), the security is much higher. That in turn means that the devices now have the ability to reach other company network resources (for example, mail servers and intranet sites). If this sounds interesting to you, contact your operator for more information.
File Integration
More and more features are packed into the new mobile devices, and these features enhance the possibilities and improve the user experience. This development is happening even faster with mobile phones—especially with Windows Mobile 2003–based Smartphones. When business users become familiar with these new features, they do not understand why a custom-built enterprise application cannot make use of this functionality. Enterprise developers are more than willing to add functionality like the ability to record voice messages, take photos, and record videos, but they need a way to integrate these functionalities with the new device capabilities. Because enterprise developers also want to use the latest (and greatest) development tools, a way to integrate managed code and the new features is needed. Figure 5 illustrates the two main options for doing this integration.
.gif)
Figure 5. Integration options
This article focuses on the example with a built-in camera. Many new Windows Mobile 2003–based Smartphones are equipped with cameras. Ideally, developers have a managed API that is available for them to use when they are integrating with the camera (see the arrow marked with a 1 in Figure 5). However, many manufacturers and mobile operators do not focus on enterprise market needs (for example, the need to use these devices as business tools that run mission-critical enterprise applications)—although there are exceptions. Therefore, managed APIs are hard to find. The mobile developer community has provided some wrappers. With specific devices, smooth integration is possible. But for most devices, there are no managed APIs and no APIs at all. However, for devices with Windows Mobile 5.0, the .NET Compact Framework 2.0 offers a managed API for integration with a built-in camera. Windows Mobile 5.0 also provides some user interface support to both take pictures and to do thumbnail-based navigation of pictures.
Now the second integration option comes into play (see the arrow marked with a 2 in Figure 5). Most of the applications that ship with new devices can store their data as files in the file system. For example, the camera stores image files, and the video recorder stores movie files. A solid integration with the file system in a mobile application can somewhat compensate for the lack of managed APIs. The trade-off is that the user would need to manually navigate the different applications. The idea is that the user will use standard applications, like the one for the camera, to take the pictures and store them in the file system. The mobile application will then let the user browse the file system for image files, view the files to find the right one, and then select the file. Also, while doing these tasks, the user may also want to do basic file system manipulation like copying and pasting files. Things like creating new folders, renaming, deleting, and changing properties (attributes) of files and folders would also be welcome.
Considering this idea, it would be great to have something similar to the OpenFileDialog control (available for the desktop computers and also for Pocket PCs), but this control still lacks a number of useful features. Therefore, this article's sample includes the complete functionality to do file system manipulation as described previously. For more information, see the Code Walkthrough section later in this article.
File Upload
Another piece of the puzzle is how the captured feedback (like photos) can be transferred to the server. Even if there are many other ways of doing this, a very simple and therefore powerful way is to upload the files directly to a Web server, as shown in Figure 6.
.gif)
Figure 6. Uploading files by using HTTP
If the Web server is configured correctly, the client uses an HTTP PUT operation to send the file to the server (see the arrow marked with a 1 in Figure 6). When the file is transferred, the Web server sends back a confirmation to the client (see the arrow marked with a 2 in Figure 6). For more information, see the Code Walkthrough section later in this article.
Notification Infrastructure
After a new delivery is created in the back-office, the driver who has been assigned the new delivery must be instantly notified. Notifying the driver is the second step of the business process, as noted earlier in this article. Figure 7 illustrates how the notification is made.
.gif)
Figure 7. Notification architecture
Each client first notifies the server how it can be reached (it reports its current IP address with a XML Web service call). See the arrow marked with a 1 in Figure 7. When a new delivery is created in the back-office Web application (and saved in the database), a notification is instantly sent to the client by using Transmission Control Protocol/Internet Protocol (TCP/IP) sockets (see the arrow marked with a 2 in Figure 7).
For more information about other notification architectures and technical solutions, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
MapPoint Web Service Integration
Throughout the delivery business process, the driver can be given geographical information to ease both the planning and the actual delivery. Although there are many technical solutions available for providing the driver with both maps and driving directions, the thing that will make the application truly usable is how well the geographical solution is integrated with the rest of the application. As mentioned in the articles that are listed in the introduction of this article, XML Web services is an excellent way to do application integration. With that in mind, the MapPoint Web Service is an interesting solution to consider.
In the delivery business process, there are basically two functions for which geographical information is needed. The first function is to show a map of a specific delivery location (pick up or drop off), and the second function is to show a route from one delivery location to another. Figure 8 illustrates how both functions use the MapPoint Web Service and how a route is generated.
.gif)
Figure 8. Get route by using the MapPoint Web Service
Three subservices of the MapPoint Web Service are used to get a route between two locations. First (illustrated by the arrow marked with a 1 in Figure 8), the FindAddress Web method of the Find subservice finds the two addresses. Second, the CalculateSimpleRoute Web method of the Route subservice is used to calculate the actual route. And third, the Render subservice's GetMap Web method retrieves the maps.
The MapPoint Web Service includes much more functionality related to geographical information, and it is recommended that you consider it in more detail. For more information about using the MapPoint Web Service, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
Northwind Delivery Web Application
The back-office staff can use a Web application to create new delivery assignments. This Web application is an ASP.NET application written with Microsoft Visual Studio .NET 2003 in C# with data stored in Microsoft SQL Server 2000.
The first page of the Web application shows a list of the deliveries and their respective statuses, as shown in Figure 9.
.gif)
Figure 9. First page of the Web application. Click the thumbnail for a larger image.
The application shows how to support the initial steps in a delivery business process. The intention is not to show how this is done with regards to source code because the focus of this article is the mobile solution. However, if you want, you can examine the source code in this article's Northwind_Pocket_Delivery_Transport_WM2k3_SP.msi. For a complete walkthrough of the Web application, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
After the new delivery is created, a notification is sent to the client, as shown in Figure 10.
.gif)
Figure 10. Notification results. Click the thumbnail for a larger image.
When the notification reaches the client, it is shown to the user (the driver), as shown in Figure 11.
.gif)
Figure 11. Notification shown on a Smartphone
The delivery is ready to be transferred to the field worker (driver), and that step is done during the next synchronization. Next, this article walks through the client sample application.
Northwind Pocket Delivery Application Client Walkthrough
The example client scenario is a Smartphone application written with Visual Studio .NET 2003 in C# and targets the .NET Compact Framework.
The application shows how to support the delivery business process by using a Smartphone. The design choices align to the process as much as possible and also maximize efficiency for the driver. Some of the design choices will be commented during the walkthrough of the application. Also, this article explores parts of the code after it describes the application UI design.
Main Menu
When you start the application, the first screen is the Main menu screen, as shown in Figure 12. The main steps in this process are to get the delivery assignments, plan these assignments, pick up the packages, drop off the packages, and report the status of each delivery.
.gif)
Figure 12. Main menu
The other options in the main menu include support functionality for looking up customers (Customers), synchronizing with the server (Sync), entering application settings (Options), and getting information about the application (About).
Synchronization
The first step in the delivery process is to receive new delivery assignments by synchronizing with the server. On the Main menu screen, select Sync.
You use the Synchronize screen, shown in Figure 13, to synchronize data with the server. New assignments are transferred from the server, and completed deliveries (drop offs) are transferred back to the server. Synchronizing with the server is implemented as a two-step wizard. First, you are required to enter the user name and password for this process.
Figure 13. Synchronization
After you enter the user name and password, press Start to initiate synchronization. During the synchronization, progress is reported, as shown in Figure 14.
.gif)
Figure 14. Synchronization completed
After the synchronization is complete, press Done to return to the Main menu screen.
Plan
The next step in the delivery process is to plan the assigned deliveries. On the Main menu screen, select Plan.
You can use the Plan screen, shown in Figure 15, to search for deliveries that you want to plan. You can enter search criteria like delivery number, address, and customer name.
Figure 15. Search criteria for deliveries you want to plan
After you press Next, the matching deliveries appear in the list, as shown in Figure 16. The list includes both pick ups and drop offs, which are indicated by their respective icon (the blue up arrow for pick up and the green down arrow for drop off).
.gif)
Figure 16. Search results for deliveries you want to plan
If you press Menu, a number of commands are available, as shown in Figure 17.
.gif)
Figure 17. Menu commands
To show details for a pick up or drop off, select View. After you select View for a pick up item, the first page of the Plan Pick Up wizard is displayed, as shown in Figure 18. This first page includes information like the delivery number, the address, and a comment box.
.gif)
Figure 18. First page of the Plan Pick Up wizard
You can edit the comment text in a full screen by selecting the comment and by pressing the Action key, as shown in Figure 19.
Figure 19. Editing a comment in a full screen
When you press Next in the first page of the Plan Pick Up wizard, as shown in Figure 18, the next page of the wizard appears. This page includes information about the products to deliver, as shown in Figure 20.
.gif)
Figure 20. Products to deliver
To show detailed information about a product, select the product in the list, press Menu, and then select View. The product information displays, as shown in Figure 21.
Figure 21. Product information
Note that you can update the quantity of the products to deliver. To return to the product list, press Done to save changes or press Cancel to reject changes.
When the second page of the Plan Pick Up wizard appears (as shown in Figure 20), press Next to go to the final page of the wizard. This page includes contact information, the contact's information, and the customer's name that is related to the delivery, as shown in Figure 22.
.gif)
Figure 22. More pick up information
Press Menu to show the available commands, as shown in Figure 23.
.gif)
Figure 23. Available commands
If you select Call Contact, you can dial the number directly after you confirm it, as shown in Figure 24.
Figure 24. Confirm and dial contact's phone number
You can also send a text message or an e-mail message to a contact from the final Plan Pick Up wizard screen,, as shown in Figure 23.
If you press Menu, and then select Send Message on the final Plan Pick Up wizard screen, a new text message (SMS) is initiated, as shown in Figure 25.
Figure 25. Send text message to contact
If you press Menu, and then select Send E-mail on the final Plan Pick Up wizard screen, a new e-mail message is initiated, as shown in Figure 26.
Figure 26. Send an e-mail message to a contact
On the final Plan Pick Up wizard screen (as shown in Figure 23), you can also view a customer by selecting View Customer. The customer information screen is displayed, as shown in Figure 27.
Figure 27. Customer information
If you press Menu, similar functionality (call, send a text message, send an e-mail message) as previously described from Figure 24 through Figure 26 is available for the customer contact, as shown in Figure 28.
Figure 28. Customer functionality
On the last page of the Plan Pick Up wizard (Figure 23), you can press Finish to return to the Plan screen, as shown previously in Figure 16. On the Plan screen, you can press Menu to show the available options, as shown in Figure 29.
Figure 29. Plan deliveries
When you select View for a drop off item, the first page of the Plan Drop Off wizard appears, as shown in Figure 30. Like the first page of the Plan Pick Up wizard, this page includes the delivery number, the address, and a comment box.
.gif)
Figure 30. First page of the Plan Drop-off wizard
Press Next to go to the next page in the wizard. This page lists the products to drop off, as shown in Figure 31.
.gif)
Figure 31. Products to drop off
Press Next to go to the final page of the wizard. This page contains more delivery information, as shown in Figure 32.
.gif)
Figure 32. Contact and customer information about the drop off
Press Finish to return to the Plan screen, as shown previously in Figure 16. On the Plan screen, you can select an item in the list and then press Menu to show the commands for the selected item. You can select Move Up or Move Down to reorder the delivery items and to create a route for the assigned deliveries (pick ups and drop offs). When you are creating a route, you may find it very useful to access geographical information. To do so, first select Show on Map to get a map of the selected location, as shown in Figure 33.
Figure 33. Show a location on a map
The MapPoint Web Service is used to retrieve a map of the location by using the address of the pick up or drop off. After the map is retrieved, you can press Menu and then select Zoom In or Zoom Out to get a new map with more or less details. For example, selecting Zoom In two times results in a more detailed map, as shown in Figure 34.
Figure 34. More detailed map
Press Done to return to the Plan screen, as previously shown in Figure 16. Press Menu, and then select Route to Next to get a route from the selected location to the next location in the list, as shown in Figure 35.
Figure 35. First step of route
Both the originating and destination address are shown on this screen, and you can navigate the route by using the Next and Back (available on the Menu menu) commands, as shown in the following figures, from Figure 36 through Figure 39.
.gif)
Figure 36. Navigating a route (the second of ten screens)
.gif)
Figure 37. Navigating a route (the fourth of ten screens)
.gif)
Figure 38. Navigating a route (the sixth of ten screens)
.gif)
Figure 39. Navigating a route (the tenth of ten screens)
Because the maps are retrieved from an XML Web service, this approach provides the driver with detailed geographical information while not consuming a lot of resources on the device. This approach becomes even more powerful as you move on to the actual pick up and drop off of the deliveries.
Pick Up
The next step in the delivery process is to pick up the products you plan to deliver. On the Main menu screen, select Pick Up.
You can use the Pick Ups screen, as shown in Figure 40, to search for pick ups to make. You can enter search criteria like a delivery number, address, and customer name.
.gif)
Figure 40. Search criteria for pick ups
Press Next to view a list of the matching pick ups, as shown in Figure 41.
.gif)
Figure 41. Search results for pick ups
To show details of a pick up, select the pick up in the list, press Menu, and then select View. The first page of the Pick-up wizard appears, as shown in Figure 42. This first page includes the delivery number, the address, and a comment box.
.gif)
Figure 42. Pick up information
Press Next to go to the next page of the wizard. This page includes a list of the products to pick up, as shown in Figure 43.
.gif)
Figure 43. Products to pick up
If you need to modify the quantity of a product, select the product, press Menu, and then select View to display the product information, as shown previously in Figure 21. The main purpose of this step, however, is to mark which products were picked up. To do this, select the check box for each product.
Press Next to go to the final page of the wizard. This page includes contact and customer information about the delivery, as shown in Figure 44.
.gif)
Figure 44. More pick up information
After the pick up is completed in a satisfactory manner, select the Completed check box to make this delivery available for a drop off.
During the pick up, you may discover something that needs to be documented and reported to the back-office personnel (for example, one of the packages may have been opened before being picked up). You can start the camera software on your Smartphone (in this case a Motorola MPx220) and take a photograph of the opened package, as shown in Figure 45. On a device that uses Windows Mobile 5.0, you can implement both the camera capture functionality and thumbnail-based photo browsing in the sample application.
.gif)
Figure 45. Taking a photograph of an opened package. Click the thumbnail for a larger image.
The photo is then saved as a file, and the camera software is closed. In any of the screens in the Pick-up wizard (as previously shown from Figure 42 through Figure 44), you can select the Add File command, as shown in Figure 46.
.gif)
Figure 46. Add file command
After you select Add File, the Open File screen appears, as shown in Figure 47.
Figure 47. Open File screen
You can browse through the files by using the up and down hardware direction keys. Selecting the top folder (..) takes you one step up in the folder tree. Selecting a file or folder and then pressing Menu gives you a number of options, as shown in Figure 48.
Figure 48. File and folder options
Most of the common functionality is available. You can cut, copy, and paste files. You can rename and delete files and folders, and you can create new folders. You can see the properties (attributes) for both files and folders. You can even open applications by selecting a file and then by pressing the Action key. The associations for the respective file types are used (for example, .jpg and .gif opens Microsoft Pocket Internet Explorer). This can be convenient when you want to view a photo, as shown in Figure 49.
.gif)
Figure 49. Photo viewed in Pocket Internet Explorer. Click the thumbnail for a larger image.
To return to the sample application, press the Back hardware key. After you find the photo that you want to add, select it in the list and then press Open to get a confirmation message, as shown in Figure 50.
.gif)
Figure 50. Confirmation message after you add a photo
The file is now copied to a special folder on the device that is later used during synchronization to upload all of the files in this folder to the server. After the files are uploaded to the server, the back-office personnel will be able to see them when they look at the delivery, as shown in Figure 51.
.gif)
Figure 51. The back-off personnel can view the files that were uploaded to the server. Click the thumbnail for a larger image.
You can also add files when doing drop offs (see the Drop Off section).
Press Finish, as shown previously in Figure 44, to return to the Pick Ups screen, as shown previously in Figure 41.
Drop Off
The next and final step in the delivery process is to deliver or drop off the products picked up earlier. On the Main menu screen, select Drop Off.
You can use the Drop Offs screen, as shown in Figure 52, to search for the drop offs you are expected to make. You can enter search criteria like delivery number, address, and customer name.
.gif)
Figure 52. Search criteria for drop offs
When you press Next, the matching drop offs appear in a list, as shown in Figure 53.
.gif)
Figure 53. Search results for drop offs
To view the details of a drop off, select the drop off in the list, press Menu, and then select View. The first page of the Drop-off wizard is displayed, as shown in Figure 54. This first page includes the delivery number, address, and a box for comments.
.gif)
Figure 54. Drop off information
After you press Next, the next page of the wizard is shown. This page includes a list of the products to drop off, as shown in Figure 55.
.gif)
Figure 55. Products to drop off
If you need to modify the quantity of a product, select the product, press Menu, and then select View to display the product information, as shown previously in Figure 21. The main purpose of this step, however, is to mark which products were dropped off. To do this, select the check box for each product.
Press Next to display the final page of the wizard. This page includes contact and customer information about the delivery, as shown in Figure 56.
.gif)
Figure 56. More drop off information
After the drop off is completed in a satisfactory manner, select the Completed, check box, which will make it ready for synchronization back to the server. When the drop off is Completed, the drop off information (for example, what articles were dropped off and changes in notes) are sent back to the server during the next synchronization. Press Finish to return to the Drop Offs screen shown earlier in Figure 42.
Customers
When you select Customers on the Main menu screen, you can search for customers by company and contact name, as shown in Figure 57.
Figure 57. Customer search criteria
Press Next to view the search results, as shown in Figure 58.
Figure 58. Customer search results
When you select a product in the list, press Menu, and then select View, you can view the product details, as shown in Figure 59.
Figure 59. Product details
The screen shown in Figure 59 is the same as the screen shown earlier in Figures 27 and 28, and the functionality is identical.
Options
After you select Options on the Main menu screen, the Options screen appears, as shown in Figure 60.
.gif)
Figure 60. Options screen
The Web Service (URL) box contains the URL for the XML Web service, which is used to handle both the synchronization of newly assigned and completed deliveries and the reporting of the current IP address (used by the notification functionality). The user name in the Server Login (User) box is the default user name the application uses when synchronizing. The number in the Notification Port box is the port number used to notify the device of a new assignment. Finally, the URL in the Upload (URL) box is the URL of the Web server virtual directory that the added files (images) are uploaded to.
About
All applications should include a screen with the product name, version, copyright, and other legal information. On the Main menu screen, the About screen contains this information, as shown in Figure 61.
.gif)
Figure 61. About the application
This screen can also include a link to a Web page with product or support information.
This completes the walkthrough of the application. Because the application supports globalization (and localization), the following section also shows a few translated screens.
World Ready
When you change the regional settings (press Start, select Settings, select More, and then select Regional Settings) to Portuguese (Brazil) on your Smartphone and then restart the application, the complete application is translated. The following figures are the Brazilian Portuguese versions of the screens shown in Figures 12, 17, 18, and 35.
Figure 62 shows the translated Main menu screen, and you can see that the form's title bar and the form's controls are translated—as are the menu icon labels.
Figure 62. Translated main menu screen
Figure 63 shows the translated Plan screen. Like in the translated Main menu screen, the form title and the form controls are translated—as are the commands.
Figure 63. Translated Plan screen (search deliveries)
In Figure 64, you can see the translated information about the pick up.
Figure 64. Translated pick up information
Finally, Figure 65 shows how the first Route screen looks after being translated.
.gif)
Figure 65. Translated route screen
This concludes the walkthrough of the client application.
Code Walkthrough
The previous section provided an example client scenario for the Pocket Delivery application, and now it's time to look at the source code of that sample. The article Northwind Pocket Service: Field Service for Windows Mobile-based Smartphones covers the general parts of the code, so this article will focus on the unique aspects of this sample.
File Integration
The managed OpenFileDialog control that is available on the desktop computer and Pocket PC is not available to Smartphone developers who are targeting the .NET Compact Framework. Therefore, the sample application includes this functionality and more. It enables you to do the most common file system operations like copying, pasting, renaming, and viewing files. Things like creating new folders and changing properties (attributes) of files are also possible.
Most of the file system functionality is available in the .NET Compact Framework, but to do some of the more advanced operations, you need to make a few calls to native APIs. When doing so, note that code that calls native APIs breaks if the underlying implementation changes.
When the user selects to add a new file to a delivery (pick up or drop off), the following code runs.
private void addFileMenuItem_Click(object sender, System.EventArgs e)
{
parentForm = true;
OpenFileForm openFileForm =
(OpenFileForm)FormCache.Instance.Load(typeof(OpenFileForm));
openFileForm.Title = GlobalHandler.Translate.Text("OpenFileFormTitle",
"Open File");
openFileForm.Filter = "Image Files|*.jpg;*.gif";
openFileForm.SetFileCallback = new SetFileDelegate(SetFile);
FormCache.Instance.Push(typeof(OpenFileForm));
}
The form to open a file (OpenFileForm) is created by using the forms cache (see the Form Cache and Stack section in this article), and its properties are set. In this example, a filter is set to look only for image files. If no filter is set, the default filter (Filter="All Files|*.*") is used, and all files are shown. A callback function is defined to handle when a file is opened from the form, as shown in the following code example.
public void SetFile(string fileName)
{
int i = 1;
string destFileName;
while(true)
{
destFileName = Common.Values.FilesPath + Path.DirectorySeparatorChar +
string.Format("F{0:0000}-{1:00}",
Convert.ToInt32(this.deliveryNoLabel.Text), i) +
Path.GetExtension(fileName);
if(!File.Exists(destFileName))
break;
i++;
}
File.Copy(fileName, destFileName);
MessageBox.Show(GlobalHandler.Translate.Text("MsgFileAdded",
"File was added!"),
GlobalHandler.Translate.Text("Title", "Pocket Delivery"),
MessageBoxButtons.OK, MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button1);
}
The selected file (fileName) is copied to a folder (Common.Values.FilesPath) that the synchronization code uses later to send the files to the server. The files are named uniquely by using the delivery number and a sequential number followed by the original file extension (if the delivery number is 3, the first file is F0003-01.xxx, the second F0003-02.xxx, and so on). When the copy is complete, a message is shown to the user.
But this article should investigate what happens inside the OpenFileForm file. First, when the form is loaded, the following line of code runs.
ListViewHelper.SetGradient(itemsListView);
This call makes the ListView control get the gradient background fill that is common in most standard Smartphone applications. The code for the SetGradient method looks like the following code example.
public static void SetGradient(System.Windows.Forms.ListView listView)
{
listView.Capture = true;
IntPtr hWnd = Win32Window.GetCapture();
Win32Window.SendMessage(hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_GRADIENT);
listView.Capture = false;
listView.Refresh();
}
This code uses some of the interoperability functionality in the Smart Device Framework, which is also available with source code, from OpenNETCF.
When the initial directory (path) is set, the following code fills the ListView control with files from the file system.
ListViewItem lvi;
itemsListView.BeginUpdate();
itemsListView.Items.Clear();
// If not root
if(path.Length > 1)
{
// Add "up" folder
lvi = new ListViewItem(UPDIR);
lvi.ImageIndex = 0;
itemsListView.Items.Add(lvi);
}
// Add folders
string[] dirs = Directory.GetDirectories(path);
ArrayList list = new ArrayList(dirs.Length);
for(int i = 0; i < dirs.Length; i++)
list.Add(dirs[i]);
list.Sort(new SimpleComparer());
foreach(string dir in list)
{
lvi = new ListViewItem(Path.GetFileName(dir));
lvi.ImageIndex = 0;
itemsListView.Items.Add(lvi);
}
// Add files
string[] filters = this.filter.Split('|')[1].Split(';');
list = new ArrayList();
foreach(string fileFilter in filters)
{
string[] files = Directory.GetFiles(path, fileFilter);
for(int i = 0; i < files.Length; i++)
list.Add(files[i]);
}
list.Sort(new SimpleComparer());
foreach(string file in list)
{
lvi = new ListViewItem(Path.GetFileName(file));
lvi.ImageIndex = 1;
//lvi.SubItems.Add("file size");
itemsListView.Items.Add(lvi);
}
itemsListView.EndUpdate();
if(itemsListView.Items.Count > 0)
{
itemsListView.Items[0].Selected = true;
itemsListView.Items[0].Focused = true;
}
If this is not the root of the file system, a top folder (..) item is added to the list. Then, the folders are added, followed by the files (matching all of the specified filters). Both folders and files are sorted before they are added to the ListView control. Finally, the first item in the list is selected.
The list of folders and files are navigated as usual with the up and down direction keys, but because the list may be extensive, a page-up and page-down functionality has been added. The left and right direction keys are used for this functionality, and the code is implemented in the KeyUp event of the ListView control, as shown in the following code example.
private void itemsListView_KeyUp(object sender, KeyEventArgs e)
{
int i = 0;
int lineNo = 0;
if((e.KeyCode == Keys.Left) || (e.KeyCode == Keys.Right))
{
e.Handled = true;
i = ListViewHelper.GetTopIndex(itemsListView);
lineNo = itemsListView.SelectedIndices[0] - i;
}
switch(e.KeyCode)
{
case Keys.Right:
i += 19;
if(i > itemsListView.Items.Count)
i = itemsListView.Items.Count - 1;
break;
case Keys.Left:
i -= 10;
if(i < 0)
i = 0;
break;
}
if(e.Handled)
{
itemsListView.EnsureVisible(i);
i = ListViewHelper.GetTopIndex(itemsListView) + lineNo;
itemsListView.BeginUpdate();
itemsListView.Items[i].Selected = true;
itemsListView.Items[i].Focused = true;
itemsListView.EndUpdate();
}
}
Again, a helper method (GetTopIndex) that calls native APIs is used to get the row number of the topmost row in the ListView control. Then, the list is navigated one page at a time—either up or down—depending on what direction key the user presses.
When an item is selected (when the user presses the Action key), the following code runs.
ListViewItem lvi = itemsListView.Items[itemsListView.SelectedIndices[0]];
bool isFolder = lvi.ImageIndex == 0;
if(lvi.Text == UPDIR)
{
path = path.Substring(0, path.Substring(0,
path.Length – 1).LastIndexOf(Path.DirectorySeparatorChar) + 1);
fillList();
}
else if(isFolder)
{
path += lvi.Text + Path.DirectorySeparatorChar;
fillList();
}
else
ShellExecute.Start(path + lvi.Text);
If the current item is either the top folder (..) or a subfolder, the current folder is changed and the list is updated. If the current item is a file, another helper call is used, as shown in the following code example.
public static void Start(string fileName, string parameters)
{
int nSize;
SHELLEXECUTEEX see;
IntPtr pFile;
IntPtr pParams;
see = new SHELLEXECUTEEX();
nSize = fileName.Length * 2 + 2;
pFile = localAlloc(MemoryAllocFlags.LPtr, nSize);
Marshal.Copy(Encoding.Unicode.GetBytes(fileName), 0, pFile, nSize - 2);
nSize = parameters.Length * 2 + 2;
pParams = localAlloc(MemoryAllocFlags.LPtr, nSize);
Marshal.Copy(Encoding.Unicode.GetBytes(parameters), 0, pParams,
nSize - 2);
see.lpFile = pFile;
see.lpParameters = pParams;
ShellExecuteEx(see);
LocalFree(pFile);
LocalFree(pParams);
}
Although this code might look a bit confusing for a pure .NET Compact Framework developer, it basically fills a native structure (SHELLEXECUTEEX) with the name of the application and the parameters that are passed to the native API (ShellExecuteEx). You should use this specific API because it looks up the respective application associated with the file extension of the selected file. If you only want to open files of a specific type (in this case, image files), you could use the OpenNETCF.Diagnostics.Process.Start method. For more information, see the Initiating Calls and Sending Text and E-Mail Messages section in this article.
When the user selects the Open command, the following code runs.
ListViewItem lvi = itemsListView.Items[itemsListView.SelectedIndices[0]];
this.fileName = path + lvi.Text;
this.setFileCallback(fileName);
this.Close();
The full path of the selected file is saved and passed by using the callback method (see the receiving side of the code earlier in this article).
This concludes the review of the source code that you need to select a file in the file system, but as this article mentioned earlier, the OpenFileForm implementation offers a lot of general file system manipulation functionality. The following code example is for the Cut, Copy, and Paste commands.
private void cutMenuItem_Click(object sender, System.EventArgs e)
{
ListViewItem lvi =
itemsListView.Items[itemsListView.SelectedIndices[0]];
clipboardFileName = path + lvi.Text;
clipboardAction = ClipboardAction.Cut;
}
private void copyMenuItem_Click(object sender, System.EventArgs e)
{
ListViewItem lvi =
itemsListView.Items[itemsListView.SelectedIndices[0]];
clipboardFileName = path + lvi.Text;
clipboardAction = ClipboardAction.Copy;
}
private void pasteMenuItem_Click(object sender, System.EventArgs e)
{
// Check if file exists
string dest = path + Path.GetFileName(clipboardFileName);
if(File.Exists(dest))
{
if(MessageBox.Show(
GlobalHandler.Translate.Text("MsgDestExistOverwrite?",
"Destination already exist, overwrite?"), this.Text,
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) == DialogResult.Yes)
File.Delete(dest);
else
return;
}
// Move or copy
string s = path.Substring(0, path.Length - 1);
switch(clipboardAction)
{
case ClipboardAction.Cut:
File.Move(clipboardFileName, dest);
break;
case ClipboardAction.Copy:
File.Copy(clipboardFileName, dest, false);
break;
}
clipboardAction = ClipboardAction.None;
clipboardFileName = string.Empty;
fillList();
}
This edit-menu functionality (cut, copy, paste) is implemented by using a simplified clipboard that two private variables implement. One variable indicates whether the operation is a cut or copy operation (clipboardAction), and the other string variable (clipboardFileName) holds the currently cut or copied file name. The Cut and Copy commands simply set the two variables. The Paste command uses the Move or Copy method of the file class after checking whether the destination file already exists.
The same Move method is also used when renaming a file. The following code is for the Delete command.
private void deleteMenuItem_Click(object sender, System.EventArgs e)
{
ListViewItem lvi = itemsListView.Items[itemsListView.SelectedIndices[0]];
bool isFolder = lvi.ImageIndex == 0;
string s = GlobalHandler.Translate.Text("MsgDeleteFile?",
"Are you sure you want to delete") + " " + lvi.Text;
if(isFolder)
s += " " + GlobalHandler.Translate.Text("MsgDeleteContent?",
"and all its content");
s += "?";
if(MessageBox.Show(s, this.Text,
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
if(isFolder)
Directory.Delete(path + lvi.Text, true);
else
File.Delete(path + lvi.Text);
fillList();
}
}
After the user confirms the deletion—and depending on whether the selected item in the list is a folder or a file—the Delete method of the respective class (Directory or File) is used.
The New Folder command uses the Directory.CreateDirectory method and the FileInfo and DirectoryInfo classes to manipulate the attributes of folders and files. For details about the implementation of the commands, see this article's Northwind_Pocket_Delivery_Transport_WM2k3_SP.msi.
File Upload
Although using XML Web services is the preferred way of making calls to a server, it can sometimes be very efficient to do a simple upload of a file. There are several ways of doing that, and File Transfer Protocol (FTP) is one. A more straightforward way would be to use HTTP. It has the advantages that it "talks" over the common Web server port (80) and that it is not as "chatty" as FTP. The code to upload a file to a Web server looks like the following.
public static string UploadFile(string sourceFile, string destinationFile)
{
// Read file
BinaryReader rdr = new BinaryReader(File.OpenRead(sourceFile));
byte[] data = rdr.ReadBytes((int)rdr.BaseStream.Length);
// Create PUT request
Uri uri = new Uri(destinationFile);
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "PUT";
//request.SendChunked = true; // maybe if large files (> 50K)
request.ContentLength = data.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
// Get response, and return
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
HttpStatusCode statusCode = response.StatusCode;
return "Request status: " + statusCode.ToString();
}
The file is read into a buffer (data) that is sent by using a HTTP PUT operation request, and then the response status code is returned to the caller. To increase the reliability of large files coming through, you may want to enable the data to be sent in segments (set SendChunked=true on the request object).
Initiating Calls and Sending Text and E-Mail Messages
As shown in the sample walkthrough, several menu items integrate with the phone's ability to make phone calls and to send text (SMS) and e-mail messages. Examples include the phone numbers and e-mail addresses of contacts. The integration with the standard Smartphone functionality is done by using the Web browser (Pocket Internet Explorer).
When the user selects the Call Contact command, the following line of code runs.
Process.Start("iexplore.exe", "tel:" + phoneLabel.Text);
The Process class is included in the Smart Device Framework, which is also available with source code, from OpenNETCF. The Start method opens an application with the provided parameter string. In this example, Pocket Internet Explorer opens with a phone number link as the parameter. You can achieve the same result by entering the link in the address bar of Pocket Internet Explorer on the Smartphone. The result is that the device asks (with a confirmation message) if you want to call the phone number (as shown earlier in Figure 24).
A very similar approach is used for sending text messages, as shown in the following code.
Process.Start("iexplore.exe", "mailto:" + phoneLabel.Text);
The logic is the same as it is for the phone number links. The standard application for sending text messages is opened (by Pocket Internet Explorer) with a new message initiated with the provided phone number (as shown earlier in Figure 25).
Again, the logic for sending e-mail messages is very similar, as shown in the following code.
Process.Start("iexplore.exe", "mailto:" + emailLabel.Text);
For more information about other available options for sending e-mail messages from managed code, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
Notification Infrastructure
Before notifications of new deliveries can be sent to the Smartphone, the server needs to be informed about the device's current IP address. This is done on the device by using the following code.
WebServices.Delivery deliveryWebService = new WebServices.Delivery();
deliveryWebService.ReportIpAddress(Common.Values.EmployeeID,
Dns.Resolve(Dns.GetHostName()).AddressList[0].ToString());
The Web service proxy instance (deliveryWebService) is implemented on the server to simply store the sent IP address in the database. Then, when the user creates a new delivery, the server uses the IP address to connect to the device using sockets. On the device, there is a listener class running on a background thread that listens for incoming notification, as shown in the following code.
TcpListener tcpListener =
new TcpListener(Common.Values.NotifyListenerPort);
tcpListener.Start();
while(listenerThreadActive)
{
// Look for notification
if(tcpListener.Pending())
{
// Get notification message
TcpClient tcpClient = tcpListener.AcceptTcpClient();
Stream s = tcpClient.GetStream();
Byte[] buffer = new Byte[250];
int bytes = s.Read(buffer, 0, buffer.Length);
string message = Encoding.ASCII.GetString(buffer, 0, bytes);
// Send back confirmation
string response = "OK";
Byte[] responseBytes =
Encoding.ASCII.GetBytes(response.ToCharArray());
tcpClient.GetStream().Write(responseBytes, 0, responseBytes.Length);
tcpClient.Close();
showNotification(message);
}
Thread.Sleep(1000);
}
When a notification is received (by using sockets), it is shown to the user as an ordinary message box, as shown in the following code.
private void showNotification(string message)
{
MessageBox.Show(message, GlobalHandler.Translate.Text("Title",
"Pocket Delivery"), MessageBoxButtons.OK, MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button1);
}
For more information about how the notification infrastructure is implemented in the sample, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
MapPoint Web Service Integration
In the sample application, the MapPoint Web Service is used in two ways. The first way is to simply show a map of a selected location (address), and the second is to show a route between two selected locations (addresses).
For more information about how to implement the MapPoint Web Service integration, see the article Northwind Pocket Delivery: Transportation for Windows Mobile-based Pocket PCs.
GlobalHandler
Any enterprise mobile solution that is intended to be used in more than one language needs to be easily translated. Therefore, you can use the GlobalHandler class to translate complete forms—including all controls and menus. It only requires a single line of code in each form, as shown in the following code example.
GlobalHandler.Translate.Form(this);
Even simple texts, such as error messages, can be translated by using the following format, as shown in the following code example.
MessageBox.Show(GlobalHandler.Translate.Text("MsgCantOpenWebPage",
"Could not open web page!"), this.Text);
For more information about the code related to globalization and the management of that code, see the article Northwind Pocket Sales: Field Sales for Windows Mobile-based Pocket PCs.
Form Cache and Stack
Each enterprise application that contains a large amount of forms requires that the forms—and the memory they consume—be managed in an efficient way. Therefore, the FormCache class supports both the caching and stacking of forms. Briefly, the loading of a new form, or actually the pushing of a new form on the form stack, looks like the following code example.
FormCache.Instance.Push(typeof(SalesForm));
The push implicitly loads the form if it is not already loaded. If any parameters need to be passed to the new form, the code looks like the following.
OptionsForm optionsForm = (OptionsForm)
FormCache.Instance.Load(typeof(OptionsForm));
optionsForm.DatabaseExist = databaseExist;
FormCache.Instance.Push(typeof(OptionsForm));
For more information about the code related to caching and stacking forms and the management of that code, see the article Northwind Pocket Sales: Field Sales for Windows Mobile-based Smartphones.
Conclusion
If the managed APIs are missing, integrating your application with other applications by using the file system is a straightforward and viable solution. If your enterprise application has good support for file system manipulation, that support will help you overcome some integration issues. File integration provides a way to get started quickly when integrating with things like voice recorders, built-in cameras for photo and video, and GPS receivers. That way, your application's users can start making those gadgets that create business value. You can use the provided Northwind_Pocket_Delivery_Transport_WM2k3_SP.msi to get started writing those enterprise applications right away.