Chapter 16. Using Maps

This chapter covers

  • Launching the built-in Maps application
  • Determining device location
  • Drawing movement on an embedded map
  • Querying an address for a location

One of the appealing features of a smartphone like the Windows Phone is the ability to quickly discover your location or the location of nearby landmarks, especially when it’s paired with features that provide directions between your location and a destination. Such location-aware features are made possible by two related technologies essential for mobile platforms: Map Services and Location Services. Map Services provide the user with maps, directions, and searches for nearby businesses and landmarks. Location Services can be used to determine the device’s current location based on input from the cellular and Wi-Fi networks and the Global Positioning System (GPS). The Windows Phone SDK enables developers to access these technologies from within their applications.

The built-in Maps application can be started from within an application using tasks that launch the native application and push the running application to the background. When a more integrated user experience is desired, the developer can embed a map into an application using XAML controls provided in the SDK and the Windows Phone Toolkit.

In this chapter we demonstrate how to use Location Services to pinpoint a device’s position on the globe inside a location-aware application. In addition to providing latitude and longitude, Location Services can also provide altitude, speed, and heading. Location Services are more than a simple GPS sensor. They combine GPS, Wi-Fi, and cellular network data with a web service to provide location information. You’ll combine Location Services with the XAML Map control and explore how to display an embedded map pinpointing the user’s location and tracking their movements. We also discuss in detail how to use the Maps API to determine the user’s physical address using their current location.

Bing Maps and the GeoCoordinateWatcher

There are two different sets of Map APIs and Location Services for Windows Phone. One set is new to the Windows Phone 8 SDK and is covered in this chapter. The older set, originally part of the Windows Phone 7 SDK, is maintained in Windows Phone 8 for backward compatibility but isn’t covered in this chapter.

The older set of Maps APIs uses the Bing Maps control, BingMapsTask, and BingMapsDirectionsTask. The Bing Maps control, from the Microsoft.Phone.Maps.Controls namespace, is deprecated and shouldn’t be used in new Windows Phone 8 applications. If you use the Bing Maps control, you must manually reference the Microsoft .Phone.Maps.Controls.dll assembly found in the Windows 8 SDK libraries folder (C:Program Files (x86)Microsoft SDKsWindows Phonev8.0Libraries).

The GeoCoordinateWatcher is a .NET Framework Location Service component in the System.Device.Location namespace. Although the GeoCoordinateWatcher isn’t covered in this chapter, you’ll use other classes from the System.Device.Location namespace.

Version 8 of the Windows Phone SDK added four new Maps launchers to provide developers with an easy way to integrate maps into an application. The new launcher tasks are as follows:

  • MapsTask launches the Maps application.
  • MapsDirectionsTask launches the Maps application and displays driving directions between two points.
  • MapDownloaderTask opens the Maps Settings application and allows the user to download offline map data.
  • MapUpdaterTask opens the Maps Settings application and allows the user to update offline map data.

To highlight the Maps and Locations APIs, you’re going to build two different sample applications. First, we introduce you to maps by showing you how to build a sample that launches two of the Maps tasks.

16.1. Introducing Maps

Applications can include mapping features by either launching the native Maps application or by embedding the XAML Map control into the application user interface. In this section you’ll build a simple application to demonstrate how to use the MapsTask and MapsDirectionsTask. The sample application, shown in figure 16.1, prompts the user to enter a search term or two locations. It lets the user launch the native Maps application to show the specific location and driving directions.

Figure 16.1. The MapsTasks sample application

You’ll get started by preparing a new project with the basic user interface controls and buttons required to allow the user to interact with Maps.

16.1.1. Preparing the application

Your first sample application is named MapsTasks and is based on the Windows Phone App project template. Open Visual Studio and create the new project. The main user interface prompts the user to enter a search term or starting location and a destination location. These locations aren’t necessarily full addresses and are passed to the launchers as search terms. Open MainPage.xaml and add a StackPanel with two TextBlocks and two TextBoxes to the ContentPanel:

<StackPanel>
    <TextBlock Text="Search term or starting location:" />
    <TextBox x:Name="departureTerm" />
    <TextBlock Text="Destination:" />
    <TextBox x:Name="destinationTerm" />
</StackPanel>

The TextBoxes should be named departureTerm and destinationTerm to allow you to access their Text properties from code-behind in MainPage.xaml.cs.

The application also needs two buttons to enable the two different features in the application. The first feature opens the native Maps application with the starting location centered in the map. The second feature opens the native Maps application showing driving directions between the starting and destination locations:

<phone:PhoneApplicationPage.ApplicationBar>
   <shell:ApplicationBar>
      <shell:ApplicationBarIconButton Text="map task" Click="mapTask_Click"
            IconUri="/Assets/AppBar/feature.search.png" />
      <shell:ApplicationBarIconButton Text="directions"
            Click="directionTask_Click"
            IconUri="/Assets/AppBar/upload.png" />
   </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

The images used for the buttons come from the Windows Phone SDK. Go ahead and create empty Click event handlers for both buttons. You’ll add implementations for each Click event handler as you progress through the section. The first Click event handler will launch the built-in Maps application using the MapsTask.

16.1.2. Launching the Maps application

The built-in Maps application can be launched from any third-party application using the MapsTask launcher class. You learned how to use launchers and choosers in chapter 5. The MapsTask launcher exposes three properties to determine its behavior: Center, SearchTerm, and ZoomLevel.

Use the Center property to determine where the map is to be centered. If no value is specified for the Center property, the map will attempt to center itself at the device’s current location. The centering behavior is influenced by the search term and zoom level values specified when the task is launched, as well as locations used in previous searches.

The optional SearchTerm property is a string used to highlight specific points on the map. The search term might contain a full or partial address, a city name, or the name of a landmark. The SearchTerm might specify other type of searches as well. For example, the user could type pizzeria to find the closest restaurant serving pizzas. Locations matching the search term are identified on the map with a labeled or numbered pushpin, as shown in figure 16.2.

Figure 16.2. Searching for a local pizzeria with the MapsTask. The current location is shown on the map as a black diamond with a dot in the center, colored with the system’s theme accent color. Locations or landmarks matching the search term are marked with labeled and numbered pushpins.

The ZoomLevel controls the initial zoom level to be used to display the map. The MapsTask documentation doesn’t clarify what the appropriate values are for a zoom level, but our experimentation suggests that reasonable values are between 10 and 20.

The MapsTasks sample application uses the MapsTask when the user taps the first button in the application bar. The following listing shows the implementation of the button’s Click event handler.

Listing 16.1. Launching Maps

Before doing any work, the code checks whether the user has entered a valid search term . The MapsTask requires either the Center property or the SearchTerm property to be set and will throw an InvalidOperationException if both are empty. If the search term is valid, construct a new instance of the MapsTask and set the SearchTerm property to the value of the departureTerm.Text field. The ZoomLevel is hardcoded to 15. The Maps application is launched with a call to the Show method .

The application is now ready to test your first feature. Run the application on either your device or the emulator, enter a search term, and tap the Map task button.

Now let’s move on to implementing the second feature: displaying directions between two locations.

16.1.3. Finding directions

MapsTask doesn’t come alone. A second Maps launcher called MapsDirectionsTask provides an easy way to get directions from Maps. MapsDirectionsTask can be customized using two properties called Start and End. Both these properties are of the type LabeledMapLocation, and at least one of the two must be set or MapsDirections-Task will throw an InvalidOperationException when launched. When the Maps-DirectionsTask is launched, and either the Start or End property isn’t set, the map will use the device’s current position in place of the missing property.

The LabeledMapLocation class is used to provide a geographic coordinate along with a label for the location. If a GeoCoordinate isn’t specified in the LabledMap-Location’s Location property, MapsDirectionsTask interprets the Label property in much the same way that MapsTask interprets its SearchTerm property.

The MapsTasks sample application uses the MapsDirectionsTask when the user taps the second button in the application bar. The button’s Click event handler is shown in the following listing.

Listing 16.2. Launching Maps to calculate directions

The listing begins by declaring two LabeledMap-Location variables, one for the departure location and the other for the destination location. The LabeledMapLocations are constructed only when the user has entered a term in the related TextBox controls . To avoid an InvalidOperation-Exception, the code checks to see that at least one valid location was created . Finally a Maps-DirectionsTask is constructed and launched to show the built-in Maps application . You can see an example of the Maps application displaying turn-by-turn directions in figure 16.3.

Figure 16.3. Turn-by-turn directions as displayed in the Maps application. The starting point is labeled with a lettered pushpin, and each turning point in the list is marked on the map with a numbered dot. The route is also marked as a line between each of the turning points.

Test your second feature by running the application, entering two search terms, and tapping the Directions task button. Press the Back button to return to the application, delete one of the terms, and tap the Directions task button again. Continue to return to the application to enter different search terms until you’re comfortable with how the MapsDirectionsTask works with various combinations of search terms.

The Maps tasks are ideal for adding simple mapping features to your application that match the look and feel the user expects from a mapping application. The downside of using the Maps tasks is that your application becomes dormant when the Maps application is launched. You can keep your application alive—and more importantly keep the user in your application—by embedding a Map control right into your application.

The next sample application shows how to combine the Windows Phone 8 XAML Map control with Location Services to provide a rich map experience inside an application.

16.2. Embedding a Map control

Earlier in the chapter you learned how to use the Maps tasks to display maps to a user. What if you want a Map control inside your application, instead of launching out to the native Maps application? Have no fear: you can embed a map right inside your application.

The XAML Map control, found in the Microsoft.Phone.Maps.Controls name-space, performs most of the work necessary to render a map. This means you don’t need to write any code to interact with a web server to download tiles, manage zooming animations, or respond to user-initiated touch events. The Map control is extensible and allows the application to layer custom elements on top of the rendered map.

Although a map by itself can be fascinating, mobile phone users expect a map to provide additional features, such as tracking their position and providing a physical address for their current location. These map-related features are exposed to a developer in the form of Map and Location Services, as we’ve mentioned.

The Map Service provides a number of different APIs exposing a variety of data. These include APIs for converting an address into latitude and longitude (geocoding) and from latitude and longitude into an address (reverse geocoding), as well as an API that returns driving directions. These APIs are implemented in the GeocodeQuery, ReverseGeocodeQuery, and RouteQuery classes found in the .NET Framework names-pace Microsoft.Phone.Maps.Services.

Location Services are made up of different bits of hardware, software, and web services. The hardware includes a built-in GPS receiver, the cellular radio, and the wireless network adapter. The web service fronts a database that records the coordinates of wireless access points. The data from the web service, GPS, and cellular radio is analyzed to calculate the phone’s current longitude, latitude, and altitude. All this complexity is hidden behind the interface of a single Windows Phone Runtime class called Geolocator, found in the Windows.Devices.Geolocation namespace. Geolocator provides the properties, methods, and events that an application uses to read location data.

Note

The ID_CAP_MAP capability must be declared in the WMApp-Manifest.xml when using the Map control or the Map Service. Likewise, the ID_CAP_LOCATION capability must be declared in order to use the Geolocator.

To learn how to use the Map control, query the Map Service, and retrieve location from the Geolocator, you’ll build a new sample application called LocationAndMaps.

16.2.1. Building the LocationAndMaps sample application

Start the new sample application by creating a new Windows Phone App named LocationAndMaps. This project will use the Windows Phone Toolkit, so go ahead and use the NuGet Package Manager to add a reference to the toolkit assembly. The application is fairly simple, displaying two TextBlocks and a Map. The application is shown in figure 16.4.

Figure 16.4. The LocationAndMaps sample application

The first TextBlock displays the Status reported by the Geolocator, and the second TextBlock displays information about the current location. The two TextBlocks are placed in a StackPanel, which is placed in the ContentPanel in MainPage.xaml, as shown in the following listing.

Listing 16.3. The XAML markup for the LocationsAndMaps main page

As we mentioned, the Map control is located in the Microsoft.Phone.Maps.Controls namespace. The XAML compiler doesn’t automatically recognize this namespace, so you need to add an xmlns attribute to the top of the MainPage.xaml file . The sample application displays the Map control in the second row of the ContentPanel Grid control in the LocationAndMaps project’s MainPage.xaml file.

Tip

The maps xml namespace is added automatically if you use the Visual Studio Toolbox to drag and drop a Map control onto the Visual Studio Designer.

Drag, pinch, and other gestures supported in the native Maps application are supported in the Map control. The application generated from listing 16.3 is shown in figure 16.5.

Figure 16.5. The LocationAndMaps sample application displaying a map

If you run the application now, you should see the Map control displayed in the bottom half of the phone’s screen. But the device’s current location isn’t represented on the map. The Map control doesn’t know how to obtain the device’s current location. You must determine the device’s coordinates programmatically and assign them to the map’s Center property. For the LocationAndMaps sample application, you’ll determine the device’s current coordinates with the Geolocator.

16.2.2. Centering on your current location with the Geolocator

The Geolocator is a Windows Phone Runtime class that reports location in two different ways: as a one-time asynchronous request and continuously via an event handler. If you expect that users will be relatively stationary while using your application, consider using GetGeopositionAsync. But if your use cases involve a highly mobile user—such as a tracking a daily jog or updating driving directions as the user approaches the destination—use the PositionChanged event. Let’s look at the GetGeopositonAsync first. We’ll look at continuous tracking later in the chapter.

GetGeopositionAsync, as the name implies, is an asynchronous operation that may take several seconds to complete. The Geolocator may need to turn on the cellular radio, Wi-Fi network adapter, and/or GPS receiver—which all take time. GetGeopositionAsync returns a Geoposition object containing the device’s current coordinate in its Coordinate property.

Remember that you want to query for the current device location when the application first starts up so that you can center the map and mark the user’s position. You want to do this only after the Map control has been loaded. Wire up the loaded event handler in MainPage.xaml:

<maps:Map x:Name="mapControl" Grid.Row="1" Loaded="mapControl_Loaded" />

The Geolocator is found in the Windows Phone Runtime namespace called Windows .Devices.Geolocation. Include the Geolocation namespace along with the .NET System.Device.Location namespace at the top of the MainPage.xaml.cs file, as shown in the following listing detailing the loaded event handler implementation.

Listing 16.4. Reading the device’s current location

Reading a device’s location is as easy as constructing a Geolocator and asynchronously calling its GetGeopositionAsync method . There’s a slight incompatibility between the Windows Runtime Geolocator and the .NET API Map control—they use different classes to represent a coordinate. Geolocation uses a Geocoordinate from the Windows.Devices.Geolocation namespace. The Map control uses GeoCoordinate from the System.Device.Location namespace. Fortunately, the Windows Phone Toolkit provides an extension class to help convert one to the other. In listing 16.4 the toolkit’s ToGeoCoordinate method is used to convert the Geolocator-provided coordinate before assigning it to the map’s Center property. The Map’s ZoomLevel property is changed , giving the user a closer look at their location. The coordinate’s Longitude and Latitude properties are displayed in the position TextBlock , making use of a new method called FormatCoordinate (figure 16.6).

Figure 16.6. After calling GetGeopositionAsync, the Map control’s Center property is assigned to the retrieved coordinate. The longitude and latitude are also displayed in the sample application.

The ZoomLevel controls the zoom level to be used to display the map. As with the MapsTask, the Map control’s documentation doesn’t clarify what the appropriate values are for a zoom level, and the ZoomLevel property in listing 16.4 is hardcoded to level 10.

Formatting longitude and latitude

Geolocator reports longitude and latitude as floating-point numbers representing the number of degrees east or west of the prime meridian and the number of degrees north or south of the equator, as shown in figure 16.7. Positive latitude values represent a position north of the equator. Positive longitude values represent a position east of the prime meridian. A few common formats are used to display degrees, and the sample application uses a format that breaks the number into degrees, minutes, and seconds:

Figure 16.7. Latitude is the angle measured from the equator to a particular location, as shown in the left image. The right image demonstrates how longitude is measured as the angle from the prime meridian to a particular location.

N47° 38′ 35.7″

W122° 8′ 31.1″

The FormatCoordinate method accepts an angle measurement in degrees, along with the characters to display for positive and negative values, and returns a string displaying direction, degrees, minutes, and seconds. The following listing shows the implementation of FormatCoordinate.

Listing 16.5. Formatting longitude or latitude

The listing starts by picking the character that should be shown . For example, the calling code should pass in N and S for latitude, and if the coordinate value is negative, S should be shown. Next, the value is broken up into whole degrees, minutes, and seconds, using the Math.Floor method to return the whole part of a number. To calculate the number of minutes , you subtract out the whole part of the coordinate value and multiply by 60. You do a similar operation to calculate the number of seconds. Finally, the numbers are formatted into a string.

By default, the Geolocator uses the most efficient mechanism for determining the current location. When a device’s location is calculated (possibly even in another application), it’s cached by the operating system. GetGeopositionAsync returns the cached location, if it isn’t too stale, eliminating the need to turn on hardware and query remote devices for information. If the device doesn’t have a location cached, the Geolocator uses location data calculated from nearby cellular towers or the Wi-Fi network. Usually the GPS receiver isn’t turned on unless you specifically ask for highly accurate position data. We discuss position accuracy in more depth later in this chapter.

Note

By default, the emulator believes that it’s located at Microsoft’s Redmond campus.

Now that you have the map centered, it would be nice to display a widget on it that represents the device’s location. That way, if the user scrolls the map (using gestures), they’ll still know where they are in relation to what’s shown on the screen.

16.2.3. Marking the current location on the map

One beneficial feature of the Map control is that it allows the user to change the view with pinch, zoom, and drag gestures. When the view changes, so does the programmatically assigned Center point, and the user may lose track of their current position. Adding a widget to the map that represents the current location will keep the user grounded. Because the Map control is a UI element, you could always overlay another widget over the top of it, but then you’d have to worry about converting UI coordinates to the geographic coordinates where the widget should appear and how to keep the Map and widget in sync as the user zooms and scrolls.

To deal with this scenario, the Map control acts as a container that hosts content objects and controls. The content object or control is placed into a MapOverlay, which is itself placed into a MapLayer. As shown in figure 16.8, multiple overlays can be placed into the same layer, and the Map control supports multiple layers.

Figure 16.8. The Map control displays custom objects as overlays placed into one or more layers.

A MapLayer is nothing more than a collection of overlays, and overlays are dependency objects that contain content, content templates, and positions. MapOverlay positions are specified as GeoCoordinates. The Map then handles the conversion of GeoCoordinate to screen coordinate and determines whether the overlay’s position is currently scrolled into view.

The Windows Phone Toolkit simplifies working with map overlays through the MapExtensions.GetChildren custom dependency property. The children collection allows you to add and remove any DependencyObject to/from the map. Behind the scenes, the toolkit creates the appropriate layers, overlays, and, where necessary, a content presenter.

The sample application will use MapExtensions to add a marker to the map at the device’s current location. To keep your application consistent with the look and feel of the Windows Phone, you want your widget to look as much as possible like the widget used by the built-in application. Once again the Windows Phone toolkit comes to the rescue by including UserLocationMarker, a XAML control specifically designed to show the device’s current location exactly as the native Maps application does. UserLocationMarker is derived from the toolkit’s MapChildControl, which in turn is derived from the XAML ContentControl. The following listing demonstrates how to use MapExtensions.GetChildren to add a UserLocationMarker to the map.

Listing 16.6. Add a UserLocationMarker

After providing a using statement to include the toolkit’s namespace, add a field to reference the UserLocationMarker instance . In the Map’s loaded event handler, which was created in the last section, new code is added to instantiate a UserLocationMarker and assign to the marker field. UserLocationMarker’s Geo-Coordinate property identifies exactly where the marker should be located on the map. The marker is added to the map by adding it to the collection found in the Children attached property provided by the toolkit’s MapExtensions class .

Run the application. You should now see a marker situated right in the center of the map, as shown in figure 16.9.

Figure 16.9. The LocationAndMaps sample application with a UserLocationMarker centered on the device’s current location.

Use a variety of pinch, zoom, and drag gestures to enlarge and scroll the map. The marker’s position should adjust to the changes to the Map’s view, appropriately redrawing at the screen coordinate representing the marker’s GeoCoordinate. The Map’s ability to convert screen coordinates into Geo-Coordinates is showcased again in the next section, where you add a new feature to the application that allows a user to look up an address by tapping a location on a map.

16.3. Reverse geocoding—looking up an address

Map Services provide a few different APIs exposing a variety of data. Some of these APIs convert an address into latitude and longitude (geocoding) and from latitude and longitude into an address (reverse geocoding). Map Services also perform route calculation, returning walking or driving directions from one location to another. Each of these requests is executed using a Microsoft.Phone.Maps.Services.Query<T> object. There are three different implementations of Query<T> in the Microsoft.Phone.Maps .Services namespace:

  • RouteQuery class calculates directions and returns a Route.
  • GeocodeQuery searches for GeoCoordinates of an address or search term and returns a list of MapLocations.
  • ReverseGeocodeQuery looks up an address for a given GeoCoordinate and returns a list of MapLocations.

The LocationAndMaps sample application will use a ReverseGeocodeQuery to look up an address when the user performs a tap-and-hold gesture over a location on the Map control. This code will be added to an event handler for the Map’s Hold event.

Start by wiring up the Hold event in MainPage.xaml:

<maps:Map x:Name="mapControl" Grid.Row="1"
      Loaded="mapControl_Loaded" Hold="mapControl_Hold" />

Before calling the reverse geocode service, you must create and populate a ReverseGeocodeQuery. The query requires a GeoCoordinate, which is populated with the coordinate corresponding to the location tapped by the user. The following listing demonstrates how to create and execute a ReverseGeocodeQuery in the Map’s Hold event handler.

Listing 16.7. Executing a ReverseGeocodeQuery

The method starts out by reading the tapped screen position from the GestureEventArgs instance. The screen position is converted to a GeoCoordinate with the Map’s ConvertViewportPointToGeoCoordinate method . A Pushpin control is constructed with the specified coordinate and the value of pinNumber, a field created expressly for counting the number of pins added to the map. Pushpin, another control from the Windows Phone Toolkit, can be seen in figure 16.10. The Pushpin is added to the Map’s Children attached property, and the longitude and latitude are displayed in the user interface.

Figure 16.10. A Map control displaying a numbered Pushpin and a UserLocationMarker

One more Windows Phone Toolkit feature is used to asynchronously execute the ReverseGeocodeQuery. GetMapLocationsAsync is an extension method provided by the toolkit’s QueryExtensions class that allows you to use the async/await pattern to query the Map Service . The result of the query is a list of MapLocation objects, and the user interface is updated to show the count of MapLocations returned, as well as the address of the first location. The address is formatted in a new FormatAddress method.

Note

If you choose not to use the async/await support provided by the Windows Phone Toolkit QueryExtensions class, you can execute a query by subscribing to the Query<T>.QueryCompleted event and then calling DoQueryAsync.

Formatting reverse geocoding query results

Found in the Microsoft.Phone.Maps.Service namespace, the MapLocation class declares BoundingBox, GeoCoordinate, and Information properties. In our testing, the BoundingBox property in the MapLocations returned by ReverseGeocodeQuery is always null. We also noticed that the Information class was only sparsely populated and that its Name and Description properties, as well as most of its Address properties, are empty. The FormatAddress method, shown in the following listing, accepts a MapAddress parameter and examines its properties before adding them to a formatted string.

Listing 16.8. Formatting the query results for display

FormatAddress incrementally builds an address using a StringBuilder. The MapAddress properties HouseNumber, Street, and City are added to the builder only if they contain a non-empty value. The State and PostalCode properties are added to the builder, and the whole string is returned. The resulting user interface is shown in figure 16.11.

Figure 16.11. The address retrieved by reverse geocoding a coordinate

Run the LocationAndMaps sample application now, performing tap-and-hold gestures at several locations on the map. Try to find your home, your favorite coffee shop, or a nearby landmark and see how accurately the Map Services report its address.

You now have two of the LocationAndMaps sample application features complete. The remaining feature requires continuously tracking the device location and recording the route taken on the Map control.

16.4. Continuous tracking with Geolocator

Continuous tracking is the process whereby, for one reason or another, the device’s position is recorded every few seconds or minutes. One popular category of location tracking applications allows runners or cyclists to record routes and times of their practices and races. Another popular class of applications is used to record where a car was parked and trace the route traveled from the parking lot, so a user can quickly find their way back. Perhaps the best example of continuous tracking is voice-enabled GPS navigation—those handy applications that plot driving directions and tell you when to turn.

In this section, the LocationAndMaps sample application is enhanced to allow the user to start and stop continuous tracking and to trace the device’s movements on a map. You can see an example of the route traced by continuous tracking in figure 16.12.

Figure 16.12. The LocationAndMaps application continuously tracking location. The start position is identified with a pushpin, the current position with a location marker, and the route from start to end drawn over the map. While tracking, the map appears tilted, and position information is displayed.

The sample application uses the ApplicationBar to present the user with two buttons. The first button starts the tracking with high accuracy. The second button stops continuous tracking:

<phone:PhoneApplicationPage.ApplicationBar>
   <shell:ApplicationBar>
      <shell:ApplicationBarIconButton Text="start" Click="start_Click"
            IconUri="/Assets/AppBar/transport.play.png" />
      <shell:ApplicationBarIconButton Text="stop" Click="stop_Click"
            IconUri="/Assets/AppBar/stop.png" />
   </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

The images for the buttons come from the icons library included with the Windows Phone SDK. The two Click event handlers are implemented in the next section. For now, add empty implementations of each method so that your code will compile.

You now have the skeleton in place for the continuous-tracking feature. In addition to implementing the start_Click and stop_Click methods, you need to create a member field for a Geolocator instance and hook it up to the rest of the application.

16.4.1. Working with high accuracy location data

The GPS receiver is the most accurate source of location data. This increased accuracy comes with a price, though. Activating the GPS receiver is an expensive operation, and the GPS uses a lot of battery power. Determining location from the cellular radio or the network adapter uses less battery power, with the tradeoff of decreased accuracy. The Geolocator allows the developer to specify the accuracy of location data with the DesiredAccuracy property. DesiredAccuracy can be set to one of the two values declared in the PositionAccuracy enumeration: Default or High. When reading data, the accuracy of the GeoCoordinate can be determined using the IsUnknown, HorizontalAccuracy, and VerticalAccuracy properties. Both the Horizontal-Accuracy and VerticalAccuracy properties return the accuracy range in meters.

You’ve already learned how to construct a Geolocator and ask for a single position. This time when you construct an instance of the Geolocator in the start_Click method, you assign it to a member field. Instead of calling GetGeopositionAsync, you subscribe to two events that will report status and position. The start_Click implementation is shown in the following listing.

Listing 16.9. Initializing continuous tracking with high accuracy

Before adding code to the start_Click method, create a new class-level field named service to reference a Geolocator instance. Inside the start_Click method, change the IsEnabled properties of the two application bar buttons. Construct a new Geolocator, assigning it to the service field. Set the DesiredAccuracy to High and the MovementThreshold to 1.0 meter. Subscribe to the PositionChanged and StatusChanged events. The starting coordinate is read from the marker variable and marked on the map with a new Pushpin . Update the user interface once everything is set up and ready to go: clear the position TextBlock, assign the Geolocator status to the status TextBlock, and change the Map’s Pitch property to 45.

Reporting geolocator status

The Geolocator reports its status via the Status property of the StatusChanged event. The status is reported as one of the values in the PositionStatus enumeration and is one of the following:

  • Disabled
  • Ready
  • Initializing
  • NotInitialized
  • NotAvailable
  • NoData

The sample application subscribes to the StatusChanged event and displays the current status and accuracy to the user in the service_StatusChanged method:

void service_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
   Dispatcher.BeginInvoke(() =>
   {
      status.Text = string.Format("Status: {0}  Desired accuracy: {1}",
           args.Status, service.DesiredAccuracy);
   });
}

After the event handler executes, the user sees a message similar to that shown in figure 16.13.

Figure 16.13. The status message

The Geolocator’s continuous-tracking mode is enabled once an application subscribes to the PositionChanged or StatusChanged event. The Geolocator continues to monitor and report the device’s location until the event subscriptions are removed or the application is exited or pushed to the background.

Note

Location-tracking applications can continue to run in the background if they’re designed with background operation in mind and adhere to a few constraints. Background tracking applications must extend the DefaultTask element in WMAppManifest.xml and subscribe to the PhoneApplicationService.RunningInBackgroud event. Background tracking applications can’t update the user interface while in the background. For more information, refer to the MSDN article “How to run location-tracking apps in the background for Windows Phone 8,” located at http://mng.bz/gWWn.

At this point, the LocationAndMaps application only reports changes in the Geolocator’s status. This is useful because it may take a little while for the GPS receiver to be turned on and find a signal. If the GPS satellites can’t be reached (for example, when the device is surrounded by materials that block the airwaves), it’s a good idea to inform the user. It’s not enough to report the Geolocator’s status. A continuous-tracking application needs to also report changes in position.

16.4.2. Reporting changes in position

When a devices position changes, the Geolocator raises the PositionChanged event, reporting the new Geoposition. In this section, the LocationAndMaps application is updated to display information about the new position in the user interface. In addition to reporting the current change, it would be nice to report how much it changed—how far the device traveled, how much time elapsed, and so on. Reporting changes in position is done in the service_PostionChanged method, shown in the following listing.

Listing 16.10. Handling the PositionChanged event

Start by creating a new class-level GeoCoordinate field named previous to remember the last position reported by the Geolocator and a new DateTime field named previousTime to record the time. These new fields are used to inform the user how much distance was covered and how much time elapsed between the current reading and the previous reading. Implement the service_PostionChanged event handler. Read the current Coordinate from the PositionChangedEventArgs, converting from a Geocoordinate to a GeoCoordinate. Update the position of the user location marker by calling a new UpdateMap method. The text message in the user interface is updated by calling another new method named UpdatePositionText.

UpdateMap is responsible for updating the current position as the user moves, and, eventually, drawing the user’s route on the map. The initial implementation of UpdateMap assigns the reported location to the marker’s GeoCoordinate property:

void UpdateMap(GeoCoordinate location)
{

   Dispatcher.BeginInvoke(() =>
   {
      marker.GeoCoordinate = location;
   });
}

The implementation of UpdatePositionText is shown in the next listing.

Listing 16.11. Display location in the user interface

The location properties are read from the GeoCoordinate and appended along with message text to a StringBuilder instance. When writing the longitude and latitude, call the FormatCoordinate method . In the middle of creating the message text, use the GetDistanceTo method to calculate the distance traveled since the previous value was read. Update the position TextBlock’s Text property on the UI thread. The updated user interface is shown in figure 16.14.

Figure 16.14. The position information displayed in the user interface includes altitude, heading, speed, and distance traveled, along with the estimated accuracy of the position and the length of time elapsed since the last update.

If you have a Windows Phone device handy, deploy the LocationAndMaps sample and run the application. Start continuous tracking and experiment by walking several yards in a variety of directions. Now change the DesiredAccuracy property to Default in the start_Click method, redeploy, and run the application again. How do the numbers compare between the High and Default accuracy modes? How do the numbers change as you move around? The Geolocator provides the data to pinpoint a user’s location and track a user’s movement. In the next section, you’ll extend the sample application to show the user’s movements on the Map control.

16.4.3. Displaying a route on the map

Your sample application already detects when the current position changes by subscribing to the Geolocator’s PositionChanged event. The Windows Phone Maps API makes it simple to use position data to record a device’s movement and display a route on the Map control. A route can be displayed with the MapPolyline class, found in the Microsoft.Phone.Maps.Controls namespace. A polyline is a shape made of a number of points, with a line segment drawn between each pair of points. A MapPolyline is a form of polyline that specifies its points with its Path property, which contains a collection of GeoCoordinates. The style of the line segments is specified with the Map-Polyline properties called StrokeThickness, StrokeColor, and StrokeDashed.

In this section you’ll see how easy it is to work with a MapPolyline. Start by adding a new MapPolyline member field:

using Microsoft.Phone.Maps.Controls;
using System.Windows.Media;
MapPolyline routeLine;

The routeLine is created when continuous tracking is started. Add the following code to the bottom of the start_Click method:

routeLine = new MapPolyline
{
   StrokeColor = (Color)Resources["PhoneAccentColor"],
   StrokeThickness = (double)Resources["PhoneStrokeThickness"]
};
routeLine.Path.Add(marker.GeoCoordinate);
mapControl.MapElements.Add(routeLine);

The routeLine will display its line segments using the XAML resource for the system accent color. The user specifies the system accent color in the operating system settings. The thickness of the line is specified using the XAML resource called Phone-StrokeThickness. The first point added to the routeLine is the current location as specified by the location marker. After the routeLine is initialized, it’s added to the Map control’s MapElements collection. Additional points are added to the route when the UpdateMap method is called from the PositionChanged event handler, as demonstrated in the following listing.

Listing 16.12. Updating the route shown in the map

As with the initial position, the new position is added to routeLine’s Path property . The next line instructs the Map control to zoom and scroll the route into view by calling the SetView method. SetView is passed a LocationRectangle constructed from the coordinates in routeLine’s Path property . SetView changes the Map’s zoom level to ensure that the entire route is displayed. Figure 16.15 shows a polyline on a Map control with the view adjusted to show the entire route.

Figure 16.15. A MapPolyline drawn on a Map control. When using the polyline’s collection of points as input into the Map’s SetView method, the Map will ensure the entire route is displayed.

Once again, deploy the application to your Windows Phone, launch the application, and start continuous tracking. Walk around for a while and watch as your route is drawn on the screen. With continuous tracking implemented, you’re almost finished with the LocationAndMaps application.

16.4.4. Stopping continuous tracking

Continuous tracking is enabled whenever an application subscribes to either the PositionChanged or StatusChanged Geolocator event. While continuous tracking is enabled, the device will consume battery power at a faster-than-normal rate. Applications should give the user the ability to stop continuous tracking. Before you can finish the LocationAndMaps application, you need to disable continuous tracking in the stop_Click method. The stop_Click method, shown in the following listing, stops continuous tracking and disposes of the Geolocator.

Listing 16.13. Stopping continuous tracking and releasing the Geolocator

Before releasing the service, unhook the event handlers and set the service field to null. Before exiting the method, update the user interface to inform the user that the service has been stopped, and reset the previous coordinate.

16.5. Summary

In this chapter you learned how to use launchers and a XAML control to integrate maps into an application. The MapsTask and MapsDirectionsTask launch the Maps application from your code. The XAML Map control enables you to embed maps inside your application. The Geolocator uses data from the GPS, cellular network, wireless access points, and a web service to report the phone’s longitude and latitude. The Geolocator can optionally report additional information such as altitude, speed, and heading.

Tip

If you’re interested in location-based and mapping technologies, we recommend reading the book Location-Aware Applications by Richard Ferraro and Murat Aktihanoglu (Manning Publications, 2011). You can learn more about the book at www.manning.com/ferraro.

In addition to the Maps tasks and the Map control, we looked at how to use the Map Web Services. You learned how to use one of the available Maps APIs for reverse geocoding. The Windows Phone SDK provides other Map Services to geocode an address and calculate directions between two different addresses. The built-in Map Services aren’t the only location and mapping services available to developers. Yahoo!, Google, and several other organizations provide free and fee-based mapping services.

In the next chapter we show a few techniques that use the WebBrowser control and allow you to build HTML 5 plus JavaScript applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.237.128