Windows Phone 8.1 for Developers – Maps

This blog post is part of a series about how Windows Phone 8.1 affects developers. The series is written in collaboration with Microsoft evangelist Peter Bryntesson, check out his blog here.

Update: Here you can download the sample code:

Learning how to use Maps in the .Net world is a never ending business. There are major API-differences between WPF, Silverlight, Windows 8 Store apps and Windows Phone and even between WP7 and WP8. Windows Phone 8.1 makes no differ and there are many breaking changes here. In the end of the article I will try to cover most of the namespace, class- and method-renames but first we talk about things that are more fun: the new stuff including Custom MapTiles and support for TrafficFlow.

Better support for custom map tiles

Most digital maps used today on the web and in mobile devices use the same concept of map tiles. The map is just a grid of images with the same sizes and where each image, called a map tile has an X/Y-coordinate and belongs to exactly one zoom level. For every new greater zoom level a tile is replaced by four new ones and the map gets more detailed.

For more details of the Bing Maps Tile System look here.

Many have complained about the poor support for custom map tiles in windows phone.  In 8.1 things look much better. Finally you can with little effort support your own tiles and you have more control over the different map layers.

You add/change a tiles layer with the TileSources collection where you add objects of type MapTileSource. Here you can set things like Zindex, tile pixel size and visibility. You can even allow or forbid stretching of the tiles while a higher-resolution tiles are being downloaded. The Layer property can be used to set the layer type of the tile source like BackgroundReplacement, BackgroundOverlay and RoadOverlay.

The DataSource is used to specify the actual map tile data source and can be set to any object that inherits MapTileDataSource. There are currently three derived data source classes out of the box:

  • HttpMapTileDataSource – The tiles are fetched by using HTTP or HTTPS
  • LocalMapTileDataSource – The tiles are fetched by using a local protocol such as ms-appdata
  • CustomMapTileDataSource – custom implementation where you have full control and feed the tile requests with raw pixels using IRandomAccessStreamReference

To replace the Bing map tiles with tiles from OpenStreetMap:

var httpsource = new HttpMapTileDataSource("{zoomlevel}/{x}/{y}.png");
var ts = new MapTileSource(httpsource)
    Layer = MapTileLayer.BackgroundReplacement
mapControl.Style = MapStyle.None;

The old {subdomain} replacement string in the UriFormat (set in the constructor above) have been removed so if you want to add load balancing you have to use the UriRequested event:

var next = "a";
var httpsource = new HttpMapTileDataSource();
httpsource.UriRequested += (source, args) =>  
    next = GetNext(next);
    args.Request.Uri = new Uri("http://" + next + "" +
                    args.ZoomLevel + "/" + args.X + "/" + args.Y + ".png");
var ts = new MapTileSource(htds);

GetNext() is just a help function that iterates through the letters a,b and c.

If you want full control you can implement your own custom tile data source:

var customSource = new CustomMapTileDataSource();
customSource.BitmapRequested += async (o, args) => 
    var deferral = args.Request.GetDeferral();
    args.Request.PixelData = await CreateBitmapAsStreamAsync();
var ts = new MapTileSource(customSource);

where CreateBitmapAsStreamAsync() is your own method where you create/download the tile and return it as a stream.

Traffic flow

Both the map and routing now support traffic flow. To display traffic conditions on the map is as simple as:

myMapControl.TrafficFlowVisible = true;

If you want to calculate the fastest driving route with respect to traffic flow from your current location to the Jayway office in Malmö you can write:

var gl = new Geolocator() { DesiredAccuracy = PositionAccuracy.High };
var locationGeoPos = await gl.GetGeopositionAsync(TimeSpan.FromMinutes(5),
var location = locationGeoPos.Coordinate.Point;
var endPoint = new Geopoint(
new BasicGeoposition()
    Latitude = 55.6127809826285,
    Longitude = 13.0031764693558
var mapRouteFinderResult =
    await MapRouteFinder.GetDrivingRouteAsync(location, endPoint,

Routing news

In addition to the support for traffic info you can also specify some restrictions to your route query like avoid highways, toll roads, ferries, tunnels and/or dirt roads.

Here is an example with a modified query to the code above that avoids dirt roads and ferries and takes into account that we start heading south .The route is then displayed on the map and a dialogue with the navigation step by step instructions is shown.

var finderResult = await MapRouteFinder.GetDrivingRouteAsync(location, endPoint,
    MapRouteRestrictions.DirtRoads | MapRouteRestrictions.Ferries, 180);
if (finderResult.Status != MapRouteFinderStatus.Success) return;
var route = finderResult.Route;
var mapRouteView = new MapRouteView(route);
mapRouteView.RouteColor = Colors.Black;
var firstRouteLeg = route.Legs[0];
var desc = "";
foreach (var routeManeuver in firstRouteLeg.Maneuvers)
    desc += routeManeuver.LengthInMeters.ToString() + "m : " +
        routeManeuver.InstructionText + "\n";
new MessageDialog(desc).ShowAsync();

Other MapControl news

  • You can listen to touch events and get both GeoPoint and local UI coordinates related to the touch point with the MapTapped, MapDoubleTapped and MapHolding events
  • You can check if a location is visible on current map window with IsLocationInView()
  • You can see the Zoomlevels limits with MinZoomLevel and MaxZoomLevel.

API changes

One of the biggest changes in the API is that the GeoPoint class is now used everywhere the GeoCoordinate was used before. This makes the API more consistent, at the cost of more characters to write.

var endPoint = new Geopoint(
new BasicGeoposition()
    Latitude = 55.5896818824112,
    Longitude = 13.1075582373887

Another thing that have changed is how objects like pushpins are added. The old MapLayer and MapOverlay is gone. The first of two ways to do it is to just add the controls to the MapControl.Children collection. The coordinate and position origin are set by the two attached properties Location and NormalizedAnchorPoint. Here is a code example where you add a pin to the current location of the user and zoom in around the same location.

var location = await gl.GetGeopositionAsync(TimeSpan.FromMinutes(5), TimeSpan.FromSeconds(5));
map1.TrySetViewAsync(location.Coordinate.Point, 15, 0, 0, MapAnimationKind.Bow);
MapControl.SetLocation(myPushPin, location.Coordinate.Point);
MapControl.SetNormalizedAnchorPoint(myPushPin, new Point(0.5, 0.5));

The second way is to add e.g a MapIcon to the MapElements property.

Some other changes worth mentioning:

  • No more need for a map capability (ID_CAP_MAP)
  • The query classes (RouteQuery, GeocodeQuery, ReverseGeocodeQuery) has been replayed with the two finder classes MapRouteFinder and MapLocationFinder.
  • The MapControl.Routes property replaces the Add/RemoveRoute methods.
  • The SetView methods is made async with TrySetViewAsync.
  • The specific EventHandler<* ChangedEventArgs> are replaced with TypedEventHandler<MapControl, Object>.

Finally here is an unstructured, probably incomplete table that tries to map old namespaces, classes and methods to their new names:

Have fun mapping around!

Update: Here you can download the sample code:

Microsoft.Phone.Maps.Controls  ➝ Windows.UI.Xaml.Controls.Maps
Microsoft.Phone.Maps.Services  ➝ Windows.Services.Maps
Map  ➝ MapControl
Map.Center(GeoCoordinate)  ➝ MapControl.Center(Geopoint)
Map.ColorMode(MapColorMode)  ➝ Map.ColorScheme(MapColorScheme)
Map.LandmarksEnabled  ➝ MapControl.LandmarksVisible
Map.PedestrianFeaturesEnabled ➝ MapControl.PedestrianFeaturesVisible
Map.Pitch ➝ MapControl.DesiredPitch
Map.ActualPitch ➝ MapControl.Pitch
Map.Add/RemoveRoute(MapRoute) ➝ MapControl.Routes(MapRouteView)
Map.CartographicMode ➝ MapControl.Style
MapCartographicMode ➝ MapStyle
Map.TileSource(TileSource) ➝ MapControl.TileSource(MapTileSource)
Map.TransformCenter ➝ MapControl.TransformOrigin
Map.GetMapElementsAt() ➝ MapControl.FindMapElementsAtOffset()
Map.SetView ➝MapControl.TrySetViewAsync()
Map.SetView ➝ MapControl.TrySetViewBoundsAsync()
Map.ConvertViewportPointToGeoCoordinate ➝ MapControl.GetLocationFromOffset()
Map.ConvertGeoCoordinateToViewportPoint ➝ MapControl.GetOffsetFromLocation()
Map.ResolveCompleted(e) ➝ MapControl.LoadingStatusChanged(e)
Map.Layers ➝ MapControl.Children
Map.MapRoute ➝ MapControl.MapRouteView
MapsApplicationContext.AuthenticationToken ➝ MapControl.MapServiceToken
MapsApplicationContext.ApplicationId ➝ In Package.appxmanifest:
GeoCoordinateCollection ➝ Geopath
LocationRectangle ➝ GeoboundingBox
Route ➝ MapRoute
RouteLeg ➝ MapRouteLeg
RouteManeuver ➝ MapRouteManeuver
Route.Geometry ➝ MapRoute.Path
RouteLeg.Geometry ➝ MapRouteLeg.Path
RouteManeuver.InstructionKind ➝ MapRouteManeuver.Kind
RouteManeuverInstructionKind ➝ MapRouteManeuverKind

This Post Has 24 Comments

  1. Dave

    Is this control also available for Windows Store apps?

  2. Andreas Ekberg

    Dave: No, at the moment you have to use the old separate Bing Map control for Windows Store apps. But looking at the naming of the namespaces I dare to say that this most probably will be added to Windows Store apps next time they update the API:s.

    1. Herman van der Blom

      Ok thats why I cant find the namespace Windows.Services.Maps. I am developing a universal app and tried to convert the Nokia map to new wp8.1

      1. Andreas Ekberg

        Herman: Yes, thats correct, you can’t add a reference to Windows.Services.Maps to the Windows Project or the shared parts. Intellisense can find the namespace if you select the phone project in the left dropdown (Ctrl + F2) but if you add a reference to it, the windows 8 Project wouldn’t build.

  3. cuong le

    Hi Andreas Ekberg!
    I’m building openstreetmap applycation for windows phone 8.1. But i’m beginer. I don’t understand clearly this. Could help me in detail? i really need your help. because I will have to present this issue in early June.
    Thanks you very much!

  4. Frank

    Hi Andreas,

    I have been trying the MapControl for Windows Phone 8.1. I’m new to this and I have done some research but I haven’t managed to create a proper “pushpin” on top of the Map with the new API changes (MapOverlay is gone).

    I created a DependencyObject but all I can see in the map is a text that refers to Windows.UI.Xaml.Controls.Maps.MapIcon instead of the icon itself. I checked the class “Pushpin” but I didn’t see what information I should have in order to have a pushpin with a custom icon from code (not from xaml).

    Any suggestion?

    Thanks a lot

  5. Frank

    Hi Andreas,

    Just forgot to add that I have tried to add children but not even this example worked: (zoomed in and out several times)

    Windows.UI.Xaml.Shapes.Ellipse fence = new Windows.UI.Xaml.Shapes.Ellipse();

    MapControl.SetLocation(fence, point);
    MapControl.SetNormalizedAnchorPoint(fence, new Point(0.5, 0.5));

    So, basically, any children (i.e. pushpin) added from code is not visible and there’s no overlay data.

    Any suggestion is highly appreciated

    Thanks again

  6. Salwa Ismail

    please send me code for cluster map with windows phone 8.1

  7. Gianluca

    Hello! Thank for the info.. i’m a neofite of WP8.1 apps and i’m trying learn as much as I can of this enviroment. For my background as a webmaster i build my apps in HTML+JS (not really expert in VB or C#) but i have troubles finding simple “howto” different from the basic ones from MSDN.
    For example i’ve found this howto: to add map to an APP but i can’t find the same one in JS… where can i find some info? Some sites with example and API explanations in Javascript?
    Thank you very much!!!!

  8. Armin

    Hey! I have problem, when I add Image into Map children. Image is always visible. but when i manipulate (zooming, moving) with map, image is shaky. I want to be like Pushpin in WP8, that’s always in same loaction and it’s not shaky. Any suggestion?

  9. Tho Nguyen

    I’m an Android-iOS Dev.
    I am starting with Windows Phone.
    I want porting some App to WP by C# language (native app for perform). But Map API 8.0 and 8.1 run only one.
    How did I do?

  10. Viacheslav


    I got invalid data when call ConvertViewportPointToGeoCoordinate method of the Map control. To reproduce it you should set ZoomLevel to the 0 and call the ConvertViewportPointToGeoCoordinate metod with (0, 0) screen point position. The method returns an invalid value for the high latitudes.

    That issue was introduced in 8.1 DP and not fixed yet.

    Could you help me to find a workaround to avoid a negative effect of this issue?

    1. Andreas Ekberg

      Sorry, not following you, I get an runtime exception when I try to set ZoomLevel to 0, 1 is the lowest allowed value. I don’t think its odd that you get strange values if you click for instance outside the map. Isn’t the simple workaround to just handle the limit values different with a simple if statement. It seems that you easily can find out a pattern.

  11. Ha qui

    I want to draw circle on map. I want when zoom level change this circle can change too. I do not find class Mapoverlay in Windows Phone 8.1 RT. Can you help me? Please…

  12. srikanth

    hi, If I want to do my custom route u sing my latitude,longitute how I can do?

  13. Will

    How would you go about adding a user location icon and have it function like the stock map app? I’m trying to figure out how to get the users heading to change as they move. Or have the map locked to the users heading and rotate the map with the user icon direction locked.

    Is any of this functionality built into the map control? Or does it all need to be custom built?

  14. Anish Jhaveri


    Great article! I am facing one issue with map control.

    foreach (SyncLocationTable location in locationList)
    Image pin = new Image();
    pin.Source = GetImageURI(location);
    pin.Tag = location;
    pin.Tapped += pin_Tapped;

    var loc = new Geopoint(new BasicGeoposition() { Latitude = location.latitude, Longitude = location.longitude });

    MapControl.SetLocation(pin, loc);
    MapControl.SetNormalizedAnchorPoint(pin, new Point(0.5, 0.5));

    map1.Children.Add(pin); //map1 is the MapControl in xaml

    All works fine when I attach the phone and run the application from Visual Studio, all the pins gets displayed on maps. But, when I package the app and upload it to Windows Phone Store OR deploy the bundle to phone using App Deploy tool, the pins don’t appear!

    The Application ID and Authentication Token are correct. Can you please help me with this?

Leave a Reply