×

Guide to the Windows Phone 8 Maps API

This guide describes how to use the new Windows Phone 8 Maps APIs. A simple browser application featuring maps – Map Explorer – is used as an example. Whether you are upgrading an application that uses Bing Maps, enhancing your already existing application by introducing a Map control, or starting to develop a whole new maps-based application with such features as keyword search, route directions and locationing, this guide will help you to accomplish your task.

It is recommended to use this guide as a companion to Map Explorer, which is a simple Windows Phone 8 application combining the topics of this article into a single implementation. Code snippets and screenshot images in this guide are taken from the Map Explorer.

A lot of information in this article is based on Windows Phone 8 developer documentation, which contains several code snippets of map usage and services, as well as detailed API and class documentation.

Maps API overview

This section provides an overview to the fundamental APIs with which fully featured Map applications can be developed. The new Windows Phone 8 Maps APIs are divided into two namespaces. Microsoft.Phone.Maps.Controls namespace contains the most important class of any Map-based application, Map control, with all the necessary auxiliary classes. Microsoft.Phone.Maps.Services namespace, on the other hand, contains classes that provide location services to map-based applications. As it is common for a Map-based application to be location aware, two important classes from the new Windows Phone Runtime Location API are introduced. The tables below present the most important classes of these APIs. A more detailed description of the usage of these APIs can be found in other sections of this topic.

Microsoft.Phone.Maps.Controls:

Map The actual map control shown on display. May have several MapLayers and MapRoutes.
MapLayer Collection of MapOverlay objects. 
MapOverlay An object on a map layer, which positions its child UIElement objects using geographic coordinates. A map marker for a point of interest and accuracy circle around current location are examples of MapOverlays.
MapRoute Represents a route in the map control. A MapRoute is created from a Route instance.

Microsoft.Phone.Maps.Services:

GeocodeQuery Represents a geocode query object. Use to query locations based on a search term, such as "Seattle". The result of GeocodeQuery is a list of MapLocations matching the search term.
LocationInformation Contains the location information: MapAddress, description, and name of the location.
MapAddress Contains the detailed address information: country, city, postal code, street...
MapLocation Represents the location information: GeoCoordinate, LocationInformation, and the bounding box of the location.
ReverseGeocodeQuery Represents the reverse geocode query object. Use to query a MapLocation in a given Geocoordinate. The result of ReverseGeocodeQuery is a list of MapLocations.
Route Represents a path to be travelled between two or more waypoints. Consists of a list of RouteLegs and information on the route such as estimated duration and length in meters.
RouteLeg Represents the set of actions necessary to travel between two waypoints along a route. Consists of a list of RouteManeuvers and information on the route leg such as estimated duration and length in meters.
RouteManeuver Represents actions to be taken along the path of a route leg. Consists of information on the maneuver such as type of maneuver, instruction text, distance to the start of the next maneuver, and geocoordinates at the start of the maneuver.
RouteQuery Represents a route query object. Use to query a route from start coordinate to an end coordinate having 0-n waypoint coordinates in between. A travel mode for the route can be selected between driving and walking. Route can be optimised to minimise travel time or distance. The result of a RouteQuery is a Route.

Windows.Devices.Geolocation:

Geolocator Provides access to the current geographic location. Can be used for one time acquisition of current location. Can also be used to continuously track the device's location, with updates taking place after a specified time interval or when the device's location changes at least a specified distance.
Geoposition Represents a location that may contain latitude and longitude data or civic address data.

Upgrading Bing maps

As stated in the Windows Phone 8 Developer Documentation, Bing Maps control is still supported in Windows Phone 8 SDK but it is deprecated. It should only be used when upgrading Windows Phone OS 7.1 applications to Windows Phone 8. The new Map control is a much more versatile control compared to the Bing Maps control. Upgrading Bing Maps control to Windows Phone 8 Map control is straightforward, fast, and well worth the effort.

The following list summarises the changes required in upgrading an application using Bing Maps control to use the new Map control:

  • To be able to use Windows Phone 8 Map control, the application must have ID_CAP_MAP capability specified in WMAppManifest.xml file.
  • xmlns  declaration in XAML files using Map control must be changed
    • from xmlns:maps="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
    • to xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
  • using directive in corresponding code-behind file must be changed
    • from using Microsoft.Phone.Controls.Maps;
    • to using Microsoft.Phone.Maps.Controls;

New Map control does not have ZoomBarVisibility property. A good number of new configurable properties have been added instead to enable the customisation of Map control to suit your needs. The only bigger change is that there is no more PushPin class available in Windows Phone 8 Maps API. Applications are therefore required to implement the visualisation of points of interest. Implementing this visualisation has been made easy however, as will be shown later in this topic.

Map control

To be able to use the map control, the application must have ID_CAP_MAP capability specified in WMAppManifest.xml file.

Map control can be created using XAML by declaring the correct namespace and adding the map to content panel:

<phone:PhoneApplicationPage
    ...
    
    xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
    
    ...>
    
    ...
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1">
            <maps:Map x:Name="MyMap"/>
            
            ...
        
        </Grid>
        
        ...

</phone:PhoneApplicationPage>

The following example shows how Map control can alternatively be created using code:

using Microsoft.Phone.Maps.Controls;
...

public partial class MainPage : PhoneApplicationPage
{        
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        Map MyMap = new Map();
        ContentPanel.Children.Add(MyMap);
    }
    ...
}

Map properties

Map control has several properties which affect the way the map is shown on the display. Below you can find screenshots demonstrating the effects of changes in these properties.

ZoomLevel (1-20, 1 being the zoom level most zoomed out):

Heading (Directional heading pointing "up" on the map - N = 0, E = 90, S = 180, W = 270):

Pitch (the tilt of the map):

CartographicMode (road, aerial, hybrid, terrain):

ColorMode (light and dark – effect on road cartographic mode only):

LandmarksEnabled (displays 3-D object of prominent buildings and landmarks overlayed on the map when enabled):

PedestrianFeaturesEnabled (displays pedestrian features such as stairs when enabled):

h

You may define the properties of the map at creation time in XAML:

<phone:PhoneApplicationPage
     
    ...
    
    xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
     
    ...>
     
    ...

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1">
            <maps:Map x:Name="MyMap" ZoomLevel="10" Pitch="30" CartographicMode="Hybrid"/>>
       
            ...
       
        </Grid>
        
        ...

</phone:PhoneApplicationPage>

And you can just as easily access the properties from the code at any time:

public partial class MainPage : PhoneApplicationPage
{
    ...
    
    private void PitchValueChanged(object sender, EventArgs e)
    {
        if (PitchSlider != null)
        {
            MyMap.Pitch = PitchSlider.Value;
        }
    }
}

Adding graphics to a map control

It is easy to add markers on a map. In the Map Explorer, the device's current position is marked with a red map marker (Polygon). Map marker can also be some UIElement, such as an image, or even a composite element, like a Grid consisting of several UIElements. Event handlers can be added to the markers in order to add interactivity to the application. In the example below, a ReverseGeocodeQuery is used to retrieve information on the location of the map marker.

public partial class MainPage : PhoneApplicationPage 
{
    ...
     
    using System.Device.Location;
    
    ...
    
    private GeoCoordinate MyCoordinate = null;
    private ReverseGeocodeQuery MyReverseGeocodeQuery = null;

    ...
    
    private void DrawMapMarkers()
    {
        MyMap.Layers.Clear();
        MapLayer mapLayer = new MapLayer();
         
        // Draw marker for current position
        if (MyCoordinate != null)
        {
            DrawAccuracyRadius(mapLayer);
            DrawMapMarker(MyCoordinate, Colors.Red, mapLayer);
        }
         
        ...
         
        MyMap.Layers.Add(mapLayer);
    }

    private void DrawMapMarker(GeoCoordinate coordinate, Color color, MapLayer mapLayer)
    {
        // Create a map marker
        Polygon polygon = new Polygon();
        polygon.Points.Add(new Point(0, 0));
        polygon.Points.Add(new Point(0, 75));
        polygon.Points.Add(new Point(25, 0));
        polygon.Fill = new SolidColorBrush(color);
            
        // Enable marker to be tapped for location information
        polygon.Tag = new GeoCoordinate(coordinate.Latitude, coordinate.Longitude);
        polygon.MouseLeftButtonUp += new MouseButtonEventHandler(Marker_Click);

        // Create a MapOverlay and add marker
        MapOverlay overlay = new MapOverlay();
        overlay.Content = polygon;
        overlay.GeoCoordinate = new GeoCoordinate(coordinate.Latitude, coordinate.Longitude);
        overlay.PositionOrigin = new Point(0.0, 1.0);
        mapLayer.Add(overlay);
    }
        
    ...
    
    private void Marker_Click(object sender, EventArgs e)
    {
        Polygon p = (Polygon)sender;
        GeoCoordinate geoCoordinate = (GeoCoordinate)p.Tag;
        MyReverseGeocodeQuery = new ReverseGeocodeQuery();
        MyReverseGeocodeQuery.GeoCoordinate = new GeoCoordinate(geoCoordinate.Latitude, geoCoordinate.Longitude);
        MyReverseGeocodeQuery.QueryCompleted += ReverseGeocodeQuery_QueryCompleted;
        MyReverseGeocodeQuery.QueryAsync();
    }
    
    private void ReverseGeocodeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
    {
        if (e.Error == null)
        {
            if (e.Result.Count > 0)
            {
                MapAddress address = e.Result[0].Information.Address;
                String msgBoxText = "";
                
                ...

                if (address.Country.Length > 0) msgBoxText += "\n" + address.Country;
                MessageBox.Show(msgBoxText, "Map Explorer", MessageBoxButton.OK);
            } 
            ...
        }
    }
    ...
}

Retrieving current location

Retrieving the phone's current location with the new Windows Phone 8 Runtime Location API is a straightforward task. To be able to use location services, the application must have ID_CAP_LOCATION capability specified in WMAppManifest.xml file. Note that the accuracy of the location might not be right on the spot, so you may want to show it to the user with a map overlay for location approximation.

using System.Device.Location;
using Windows.Devices.Geolocation;

public partial class MainPage : PhoneApplicationPage 
{
    ...
    
    private GeoCoordinate MyCoordinate = null;
    
    private double _accuracy = 0.0;    
    
    ...
    
    private async void GetCurrentCoordinate()
    {
        ...  
        Geolocator geolocator = new Geolocator();
        geolocator.DesiredAccuracy = PositionAccuracy.High;

        try
        {
            Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromMinutes(1),
                                                                               TimeSpan.FromSeconds(10));
            _accuracy = currentPosition.Coordinate.Accuracy;
           
            ...
            
            Dispatcher.BeginInvoke(() =>
            {
                MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude); 
                ...
            });
        }
        catch (Exception ex)
        {
            // Couldn't get current location - location might be disabled in settings
            MessageBox.Show("Current location cannot be obtained. Check that location service is turned on in phone settings.");
        }
        ...
    }

    ...
     
    private void DrawAccuracyRadius(MapLayer mapLayer)
    {
        // The ground resolution (in meters per pixel) varies depending on the level of detail
        // and the latitude at which it’s measured. It can be calculated as follows:
        double metersPerPixels = (Math.Cos(MyCoordinate.Latitude * Math.PI / 180) * 2 * Math.PI * 6378137) / (256 * Math.Pow(2, MyMap.ZoomLevel));
        double radius = _accuracy / metersPerPixels;

        Ellipse ellipse = new Ellipse();
        ellipse.Width = radius * 2;
        ellipse.Height = radius * 2;
        ellipse.Fill = new SolidColorBrush(Color.FromArgb(75, 200, 0, 0));

        MapOverlay overlay = new MapOverlay();
        overlay.Content = ellipse;
        overlay.GeoCoordinate = new GeoCoordinate(MyCoordinate.Latitude, MyCoordinate.Longitude);
        overlay.PositionOrigin = new Point(0.5, 0.5);
        mapLayer.Add(overlay);
    }
    
    ...
}

Searching for an address

GeocodeQuery can be used to search location for a given search term, for example a town name or street address.

using Microsoft.Phone.Maps.Services;

public partial class MainPage : PhoneApplicationPage
{
    ...
    
    private GeoCoordinate MyCoordinate = null;
    private GeocodeQuery MyGeocodeQuery = null;

    private bool _isRouteSearch = false; // True when route is being searched, otherwise false
    
    ...
    
    private void SearchForTerm(String searchTerm)
    {
        ...
        MyGeocodeQuery = new GeocodeQuery();
        MyGeocodeQuery.SearchTerm = searchTerm;
        MyGeocodeQuery.GeoCoordinate = MyCoordinate == null ? new GeoCoordinate(0, 0) : MyCoordinate;
        MyGeocodeQuery.QueryCompleted += GeocodeQuery_QueryCompleted;
        MyGeocodeQuery.QueryAsync();
    }
    ...
}

The result of the GeocodeQuery is a list of MapLocations representing the hits matching the SearchTerm of the query. Each MapLocation has a GeoCoordinate for positioning the location on the map, as well as detailed LocationInformation with name, description and MapAddress of the location. The event handler GeocodeQuery_QueryCompleted is called both when searching the map for a keyword and when searching for a route. The route specific part is explained later on. Here the search results are stored to br later used for drawing map markers.

using Microsoft.Phone.Maps.Services;

public partial class MainPage : PhoneApplicationPage
{
    ...
    
    private List<GeoCoordinate> MyCoordinates = new List<GeoCoordinate>();
    
    private bool _isRouteSearch = false; // True when route is being searched, otherwise false 
    
    ...

    private void GeocodeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
    {
        ...
        if (e.Error == null)
        {
             if (e.Result.Count > 0)
             {
                 if (_isRouteSearch) // Query is made to locate the destination of a route
                 {
                     ...
                 }
                 else // Query is made to search the map for a keyword
                 {
                     // Add all results to MyCoordinates for drawing the map markers
                     for (int i = 0; i < e.Result.Count; i++)
                     {
                         MyCoordinates.Add(e.Result[i].GeoCoordinate);
                     }
                     ...
                 }
             }
             else
             {
                 MessageBox.Show("No match found. Narrow your search e.g. Seattle WA.");
             }
        }
        ...
    }
    ...
}

Displaying a route on a map

RouteQuery can be used to obtain a route from one geographic point to another. After using GeoCodeQuery to obtain GeoCoordinate of the destination, a RouteQuery can be made to calculate a route to that destination. Route is calculated based on travel mode (walking or driving) and way points through which the route is supposed to take. Here the route query is launched from the GeocodeQuery_QueryCompleted event handler while searching for route. This example uses only two way points for a route, beginning and destination.

public partial class MainPage : PhoneApplicationPage
{
    ...
    
    private GeoCoordinate MyCoordinate = null;
    private List<GeoCoordinate> MyCoordinates = new List<GeoCoordinate>();
    
    private RouteQuery MyRouteQuery = null;
    private bool _isRouteSearch = false; // True when route is being searched, otherwise false

    private TravelMode _travelMode = TravelMode.Driving; // Travel mode used when calculating route
    
    ...

    private void GeocodeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
    {
         ...
         if (e.Error == null)
         {
             if (e.Result.Count > 0)
             {
                 if (_isRouteSearch) // Query is made to locate the destination of a route
                 {
                     // Only store the destination for drawing the map markers
                     MyCoordinates.Add(e.Result[0].GeoCoordinate);

                     // Route from current location to first search result
                     List<GeoCoordinate> routeCoordinates = new List<GeoCoordinate>();
                     routeCoordinates.Add(MyCoordinate);
                     routeCoordinates.Add(e.Result[0].GeoCoordinate);
                     CalculateRoute(routeCoordinates);
                 }
                 else // Query is made to search the map for a keyword
                 {
                     ...
                 }
             }
             ...
         }
         ...
     }

     private void CalculateRoute(List<GeoCoordinate> route)
     {
         ...
         MyRouteQuery = new RouteQuery();
         MyRouteQuery.TravelMode = _travelMode;
         MyRouteQuery.Waypoints = route;
         MyRouteQuery.QueryCompleted += RouteQuery_QueryCompleted;
         MyRouteQuery.QueryAsync();
     }
     ...
}

The result of the RouteQuery is a RouteMapRoute is a visual representation of the Route that can be readily applied to the Map control. 

public partial class MainPage : PhoneApplicationPage
{
    ...

    private Route MyRoute = null;
    private MapRoute MyMapRoute = null;

    ...

    private void RouteQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
    {
         ...
         if (e.Error == null)
         {
             MyRoute = e.Result;
             MyMapRoute = new MapRoute(MyRoute);
             MyMap.AddRoute(MyMapRoute);

             // Update route information and directions
             ...
         }
         ...
    }
}

Displaying route directions

In order to show directions from the device's current location to a selected destination, the XAML file must be prepared for it. In Map Explorer a composition of different UI controls makes up a directions panel.

        <!--Directions from current location to destination are shown in this panel.-->
        <StackPanel x:Name="RouteDirections" Grid.Row="2" Margin="3,0,0,0">
            <TextBlock x:Name="DestinationText" Style="{StaticResource PhoneTextTitle3Style}" FontSize="{StaticResource PhoneFontSizeMediumLarge}" FontWeight="SemiBold"/>
            <TextBlock x:Name="DestinationDetailsText" Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>
        <Button x:Name="DriveButton" Content="Drive" IsEnabled="False" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,100,0" Click="TravelModeButton_Click"/>
        <Button x:Name="WalkButton" Content="Walk" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,10,0" Click="TravelModeButton_Click"/>
        <phone:LongListSelector x:Name="RouteLLS" Grid.Row="3" Margin="10,0,10,0" Background="Transparent" ItemTemplate="{StaticResource RouteListTemplate}" LayoutMode="List"
              IsGroupingEnabled="False" SelectionChanged="RouteManeuverSelected"/>

When the RouteQuery is completed, the user interface can be updated with the route information. Route is divided to RouteLegs between two way points. Each RouteLeg has a collection of RouteManeuvers representing the actions to be taken along the path of a route leg. Maneuvers themselves contain instruction text and distance details, as well as geocoordinate and maneuver type.

public partial class MainPage : PhoneApplicationPage
{
    ...
 
    private RouteQuery MyRouteQuery = null;
    private Route MyRoute = null;
 
    ...
 
    private void RouteQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
    {
         ...
         if (e.Error == null)
         {
             ...

             // Update route information and directions
             DestinationText.Text = SearchTextBox.Text;
             double distanceInKm = (double)MyRoute.LengthInMeters / 1000;
             DestinationDetailsText.Text = distanceInKm.ToString("0.0") + " km, "
                                              + MyRoute.EstimatedDuration.Hours + " hrs "
                                              + MyRoute.EstimatedDuration.Minutes + " mins.";

             List<string> routeInstructions = new List<string>();
             foreach (RouteLeg leg in MyRoute.Legs)
             {
                 for (int i = 0; i < leg.Maneuvers.Count; i++)
                 {
                     RouteManeuver maneuver = leg.Maneuvers[i];
                     string instructionText = maneuver.InstructionText;
                     distanceInKm = 0;

                     if (i > 0)
                     {
                         distanceInKm = (double)leg.Maneuvers[i - 1].LengthInMeters / 1000;
                         instructionText += " (" + distanceInKm.ToString("0.0") + " km)";
                     }
                     routeInstructions.Add(instructionText);
                 }
             }
             RouteLLS.ItemsSource = routeInstructions;

             ...

             MyRouteQuery.Dispose();
         }
         ...
    }
}

Terms of use for map services

Continued use of map services is governed by the Terms of Use. Please ensure that your application uses a valid Application ID and Authentication Token (MSDN).

Further reading

  • For further information on the Maps API in Windows Phone 8, check Maps and navigation for Windows Phone 8 (MSDN).
  • For information on how to launch and utilise the services provided by HERE location applications present on the phone, study the HERE Launchers documentation.

Last updated 27 June 2013

Back to top

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×