Complete Reference of Map Control in Windows Phone 8.1 WinRT

In this article you will learn a complete go to reference for doing any introductory work on Windows Phone 8.1 WinRt map control.

Since Windows Phone has the Windows Phone 8.1 update last year it came up with 2 different platforms to work on, Silverlight and WinRT, thus making it a bit tough to keep up with the latest API documentation and Maps are not different.

As I have written before how to use Maps following MVVM on Windows Phone 8, I'm going to keep today's one as a bit of a reference to that and will just post segments that you can use as a code sample.

Instantiating a Map in Windows Phone 8.1

Quite frankly this is the easiest job here to do actually. Let's proceed and start taking things from screenshots. First we need to open a new project targeting Windows Phone 8.1 and name it MapTest. Then I went to my Toolbox and dragged a MapControl to the middle of the Main Grid. I have already changed my map controls HorizontalAlignment and VerticalAlignment to "stretch" thus allowing the MapControl to be stretched out to the fullest for the entire app.

  1. <Maps:MapControl HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"/> 

Usually a map driven app needs an AuthenticationToken to authenticate the map services but we will focus on that later. Let's proceed to the Solution Explorer and open Package.appxmanifest and go to the Capabilities tab and make sure that both of the checkboxes for Location and Internet are checked just to make ensure your app is map capable.

map capable

Now we have a Green light to use Maps. If you are a fella from Windows Phone 8 development then you'll see now, you don't have ID_CAP_MAP here to enable the app to use maps. You only need it to have location capability.

Getting Your Own Location:

Getting your own location is still as straightforward as it was before in the Windows Phone 8 era. All you need to do is use the same Geolocator class and it looks as in the following:

  1. Geolocator locator = new Geolocator();  
  2. Geoposition position = await locator.GetGeopositionAsync(); 

Now the question remains of how to show it on a Map. Now, Windows Phone 8.1 gives you many options to choose from actually here. You can use three specific things here:

  1. MapIcon
  2. XAML controls
  3. Shapes

Using MapIcon

The first trial we will make is using the MapIcon since it is the most straight forward. MapIcon is essentially derived from the MapElement class, it can be configured by providing a new image to it or it provides a default one. And the declaration is pretty straightforward too.

  1. MapIcon icon = new MapIcon();  
  2. icon.Location = position.Coordinate.Point;  
  3. icon.Title = "My Location";  
  4. MyMap.MapElements.Add(icon); 

Now, if you want to provide a specific Image as your MapIcon, include the image in the Assets folder and let's assume the image name is MapIcon.png. All you need to do is change the Image property of your MapIcon object.

  1. icon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/MapIcon.png")); 

What people actually misinterpret here is usually they compare PushPin with MapIcon and they do have a valid reason to do so because you can achieve the same result by using both of them but in actuality it doesn't work like that. MapIcons are actually a set of Icons that define multiple purposes on the map. These are lightweight, so please choose one if you want to use these to show a specific purpose. Now our purpose was to show our current location.

Now let's put together a method named GetMyLocation() and put all these together and see what happens.

  1. private async void GetMyLocation()    
  2. {    
  3.     Geolocator locator = new Geolocator();    
  4.     Geoposition position = await locator.GetGeopositionAsync();    
  5.   
  6.     MapIcon icon = new MapIcon();    
  7.     icon.Location = position.Coordinate.Point;    
  8.     icon.Title = "My Location";    
  9.     icon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/ImageIcon.png"));    
  10.     MyMap.MapElements.Add(icon);    
  11.   
  12.     MyMap.Center = position.Coordinate.Point;    
  13.     MyMap.DesiredPitch = 0;    
  14.   
  15.     await MyMap.TrySetViewAsync(position.Coordinate.Point, 15);    
  16.        

Now, as this goes, you'll see I've done some more work too. I've changed the center property of the map control because after adding the MapIcon you need your map to focus on that point and this is how you change the center of your map. And the next thing I did is set the DesiredPitch to 0. We will see more about this property later. You definitely have noticed by now that the method is an asynchronous method because the process of locating your position is asynchronous and we're using our favourite await keyword to make locator.GetGeopositionAsync() to work synchronously inside the method. The last thing you want is to focus to the selected location (My Location) on the map. So I'm setting the map view asynchronously using the MyMap.TrySetViewAsync function and it takes two parameters, the first one being the point (the geolocation of you) you want to set your view into and the second is a zoom level of the map. It is actually setting the MyMap.ZoomLevel property in the range 1 - 20. A higher number means a greater zoom thus closer to the ground. I've also used a custom MapIcon.png with a size of 65x65 pixels. Please be careful on this one since the size you choose is the size you get on the Map. Please choose a size that looks good for your purpose. Now let's put the GetMyLocation() method OnNavigatedTo method and thus you get a smooth zooming animation.


Now, a couple of things that are missing here is a progress bar showing that the location is being detected and a try/catch that detects any exception detecting the location. Plus we need to put our location detection invocation in a button so we can tap it anytime to load our current location anytime. For that we can use an Application Bar.

Now Let's add an app bar in the bottom as in the following:

  1. <Page.BottomAppBar>  
  2.    <CommandBar ClosedDisplayMode="Minimal" Opacity="0.7">  
  3.       <AppBarButton Label="Find Me!" Icon="Target" />  
  4.    </CommandBar>  
  5. </Page.BottomAppBar> 

Now on the AppBarButton_Tapped event handler use a GetMyLocation call. It would possibly look like the following:

  1. private void AppBarButton_Tapped(object sender, TappedRoutedEventArgs e)  
  2. {  
  3.    GetMyLocation();  
  4.   

Now, let' wrap up the location detection process under a try-catch just to ensure that if anything goes wrong, you're covered. And as we'd need to show progress please put the following method in MainPage.xaml too.

  1. private async void ToggleProgressBar( bool toggle, string message="")  
  2. {  
  3.    StatusBarProgressIndicator progressbar = StatusBar.GetForCurrentView().ProgressIndicator;  
  4.    if(toggle)  
  5.    {  
  6.       progressbar.Text = message;  
  7.       await progressbar.ShowAsync();  
  8.    }  
  9.    else  
  10.    {  
  11.       await progressbar.HideAsync();  
  12.    }  
  13.   

Now all you need to do is call it to show ProgressIndicator in StatusBar, you can even provide the message in the method call.

Now GetMyLocation will look like the following:

  1. private async void GetMyLocation()    
  2. {    
  3.     ToggleProgressBar(true,"Getting your location...");    
  4.   
  5.     try    
  6.     {    
  7.         Geolocator locator = new Geolocator();    
  8.         Geoposition position = await locator.GetGeopositionAsync();    
  9.   
  10.         MapIcon icon = new MapIcon();    
  11.         icon.Location = position.Coordinate.Point;    
  12.         icon.Title = "My Location";    
  13.         icon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/ImageIcon.png"));    
  14.         MyMap.MapElements.Add(icon);    
  15.   
  16.         MyMap.Center = position.Coordinate.Point;    
  17.         MyMap.DesiredPitch = 0;    
  18.   
  19.         await MyMap.TrySetViewAsync(position.Coordinate.Point, 15);    
  20.     }    
  21.     catch (Exception ex)    
  22.     {    
  23.         MessageDialog ErrorDialog = new MessageDialog(ex.Message);    
  24.         ErrorDialog.ShowAsync();    
  25.     }    
  26.   
  27.     ToggleProgressBar(false);    
  28. }  

Using XAML controls over Map is something I really love because I was pretty fond of the PushPin control provided in Windows Phone Toolkit for Windows Phone 8. Usually this approach is more suitable for MVVM approached apps though. And as per this tutorial goes, we'd not got over MVVM just yet (we will cover that too). So, let's see how you add XAML controls or shapes in a map from code behind.

Instead of using MapIcon all you need to do know is how to generate a XAML control/Shape in the background and add it on the children list of the map control rather than the MapElements list.

So, just take off the MapIcon Segment and use this instead:

  1. private async void GetMyLocation()    
  2. {    
  3.     ToggleProgressBar(true,"Loading");    
  4.   
  5.     try    
  6.     {    
  7.         Geolocator locator = new Geolocator();    
  8.         Geoposition position = await locator.GetGeopositionAsync();    
  9.   
  10.         var pushpin = new Windows.UI.Xaml.Shapes.Ellipse();    
  11.         pushpin.Fill=new SolidColorBrush(Colors.Red);    
  12.         pushpin.Height=50;    
  13.         pushpin.Width=50;    
  14.   
  15.         MyMap.Children.Add(pushpin);    
  16.   
  17.         MyMap.DesiredPitch = 0;    
  18.   
  19.         MapControl.SetLocation(pushpin,position.Coordinate.Point);    
  20.         MapControl.SetNormalizedAnchorPoint(pushpin, new Point(0.5, 0.5));    
  21.   
  22.         await MyMap.TrySetViewAsync(position.Coordinate.Point, 15,0,0,MapAnimationKind.Bow);    
  23.     }    
  24.     catch (Exception ex)    
  25.     {    
  26.         MessageDialog ErrorDialog = new MessageDialog(ex.Message);    
  27.         ErrorDialog.ShowAsync();    
  28.     }    
  29.   
  30.     ToggleProgressBar(false);    
  31.   
  32. }  

Now, before moving to the next topic, I'd like to address some points in this approach.

  1. You can create your control in code behind as you want to build it, you can use possibly any XAML control starting from containers like a Grid or a StackPanel to a Shape like rectangle and Ellipse.

  2. Select a proper size of the shape if you want to use it and it's better than MapIcons in the sense that MapIcons are not guaranteed to be viewed.

  3. MapIcon objects are usually added to the MapElements list but this is added to the Map Children collection.

  4. You can define your datatemplate behind and even hook events (we will see this in the MVVM approach)

You need to select a proper anchor point for your XAML/Shape pushpin too. It's actually nothing but a point object in a 2D space. I want my anchor point to be in the center of the sphere. So if I put my sphere in a 2D space and 1 is the max limit in both the X and Y axis, you'd determine that (0.5, 0.5) is the center of the sphere. But this 2D co-ordinate system is actually a tad different. Kindly allow me to show in the following picture:


So, according to this rule, now you can set your anchor point properly depending on your XAML control. Just put it on an imaginary 2D grid and find your desired point. The left bottom would be (0,1) and the right bottom would be (1,1).

If you look closely you will also see we have changed our TrySetViewAsync invocation with some more parameters. Those are heading, pitch (we kept both of them at 0) and the last one is MapAnimationKind that allows you to define what kind of animation you want when setting the view. I personally love the Bow one thus I used that one and it looks as in the following:


Changing The Map Properties

The map control itself comes with many properties equipped, let's see how to change these for a chance. The first two things we'd love to change is the pitch/tilt and the rotation/heading. For that we'd need to change our layout a bit. Let's keep the map in the background and put 2 sliders (one horizontal and one vertical) for changing the rotation and pitch of the map.

We have introduced 3 rows and columns in the main grid just to keep the entire map in the background and the sliders floating in the top. The horizontal slider would change the Maps rotation and the Vertical Slider would change the Maps pitch. Now the main grid looks as in the following:

  1. <Grid>  
  2.    <Grid.RowDefinitions>  
  3.       <RowDefinition Height="Auto"></RowDefinition>  
  4.       <RowDefinition Height="*"></RowDefinition>  
  5.       <RowDefinition Height="50"></RowDefinition>  
  6.    </Grid.RowDefinitions>  
  7.   
  8.    <Grid.ColumnDefinitions>  
  9.       <ColumnDefinition Width="25"></ColumnDefinition>  
  10.       <ColumnDefinition Width="*"></ColumnDefinition>  
  11.       <ColumnDefinition Width="Auto"></ColumnDefinition>  
  12.   
  13.    </Grid.ColumnDefinitions>  
  14.    <Maps:MapControl Grid.RowSpan="3" Grid.ColumnSpan="3" x:Name="MyMap"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">  
  15.   
  16.    </Maps:MapControl>  
  17.   
  18.    <Slider x:Name="RotationSlider" Grid.Row="0" Grid.Column="1" Maximum="360"></Slider>  
  19.    <Slider x:Name="PitchSlider" Grid.Row="1" Grid.Column="2" Orientation="Vertical" Maximum="65"  ></Slider>  
  20. </Grid> 

And it looks in the emulator like this:


Now the first thing you'll notice here is that I've named the sliders accordingly. The horizontal one is called RotationSlider and the vertical one is called PitchSlider. Now, usually what we do is invoke the ValueChanged event and change the Heading or the DesiredPitch of the map. But there is a smarter way to do that. You can create two element bindings to the MyMap and bind the value of the sliders to the specific properties. If you watch carefully you will see that I have set the RotationSlider maximum value to 360 since that is the maximum rotation value and PitchSlider Maximum to 65 since that is the maximum tilt the MapControl allows. Now replace your sliders with the following binding:

  1. <Slider x:Name="RotationSlider" Grid.Row="0" Grid.Column="1" Maximum="360" Value="{Binding Heading, ElementName=MyMap, Mode=TwoWay}" ></Slider>  
  2. <Slider x:Name="PitchSlider" Grid.Row="1" Grid.Column="2" Orientation="Vertical" Maximum="65" Value="{Binding DesiredPitch, ElementName=MyMap, Mode=TwoWay}" ></Slider> 

Please make sure the Binding Mode is set to TwoWay so when the map updates the sliders update too. And without even writing a single line of backend code the feature is done!

Map -5

So, that's a creative use of element binding. Now you could've done it even from the code backend. All you need to do is go to the properties of PitchSlider and RotationSlider and create the ValueChanged method stub. The methods you would have would look like the following:

  1. private void PitchSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)  
  2. {  
  3.    MyMap.DesiredPitch = PitchSlider.Value;  
  4. }  
  5.   
  6. private void RotationSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)  
  7. {  
  8.    MyMap.Heading = RotationSlider.Value;  

Let's move on and see some of the other features we'd like to test too. Let's add two checkboxes to the bottom of the map to enable Traffic Flow and Land Marks. We added a horizontal stackpanel and added two checkboxes along with it.

  1. <StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">  
  2.    <CheckBox x:Name="TrafficCheck" Content="Traffic Flow" Foreground="Green"></CheckBox>  
  3.    <CheckBox x:Name="LandmarksCheck" Content="Land Marks" Foreground="Green"></CheckBox>  
  4. </StackPanel> 

Now, we can use a bit more of a creative element binding or use Checked and Unchecked events to change the respective map control properties. Let's see how to bind it using element binding again.

  1. <Maps:MapControl TrafficFlowVisible="{Binding IsChecked, ElementName=TrafficCheck, Mode=TwoWay}"  
  2. LandmarksVisible="{Binding IsChecked, ElementName=LandmarksCheck, Mode=TwoWay}"  
  3. Grid.RowSpan="3" Grid.ColumnSpan="3" x:Name="MyMap"  
  4. HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 

Now, watch carefully the binding written in the TrafficFlowVisible and LandMarksVisible properties. All I did here is to bind them with the appropriate checkbox IsChecked property and kept the binding mode two-way. So, anytime these properties change, even from code behind, we'll see the change on the checkbox and vice versa. Traffic Flow is a cool feature actually. See the next GIF to get an idea:


Pretty cool, huh?!

Now you can even write it on the code behind. You need to go to the properties of any of the checkbox and create the checked and unchecked property stub so you can toggle the map's TrafficFlowVisible feature. From code behind it will look like this:

  1. private void TrafficCheck_Checked(object sender, RoutedEventArgs e)  
  2. {  
  3.    MyMap.TrafficFlowVisible = true;  
  4. }  
  5.   
  6. private void TrafficCheck_Unchecked(object sender, RoutedEventArgs e)  
  7. {  
  8.    MyMap.TrafficFlowVisible = false;  

And from the XAML:

  1. <CheckBox x:Name="TrafficCheck" Content="Traffic Flow" Foreground="Green" Checked="TrafficCheck_Checked" Unchecked="TrafficCheck_Unchecked"></CheckBox> 

I still prefer the Element binding because that is extremely easy. There's one more property named PedestrianFeaturesVisible. You can try that following the same way here.

Map Appearance

The Map Control is even cool enough to let you select the Map Appearance too! Let's modify the bottom stackpanel so it can hold more buttons and add a grid with two columns. We added one combobox in each column so we can change the map color scheme and map style.

So the bottom stackpanel looks as in this now:

  1. <StackPanel Grid.Row="2" Grid.Column="1">  
  2.    <StackPanel  Orientation="Horizontal">  
  3.       <CheckBox x:Name="TrafficCheck" Content="Traffic Flow" Foreground="Green"></CheckBox>  
  4.       <CheckBox x:Name="LandmarksCheck" Content="Land Marks" Foreground="Green"></CheckBox>  
  5.    </StackPanel>  
  6.    <Grid Background="#00F9F9F9" >  
  7.       <Grid.ColumnDefinitions>  
  8.          <ColumnDefinition></ColumnDefinition>  
  9.          <ColumnDefinition></ColumnDefinition>  
  10.          </Grid.ColumnDefinitions>  
  11.          <ComboBox Grid.Column="0" PlaceholderText="Map Color" x:Name="MapColorBox" Width="150"  Background="#FF23D1B1" SelectionChanged="MapColorBox_SelectionChanged" >  
  12.             <ComboBoxItem  IsSelected="True" Content="Light" ></ComboBoxItem>  
  13.             <ComboBoxItem Content="Dark" ></ComboBoxItem>  
  14.          </ComboBox>  
  15.          <ComboBox Grid.Column="1" PlaceholderText="Map Style" x:Name="MapStyleBox" Width="150"  Background="#FF23D1B1" HorizontalAlignment="Right" SelectionChanged="MapStyleBox_SelectionChanged" >  
  16.             <ComboBoxItem  IsSelected="True" Content="None" ></ComboBoxItem>  
  17.             <ComboBoxItem Content="Road" ></ComboBoxItem>  
  18.             <ComboBoxItem Content="Aerial" ></ComboBoxItem>  
  19.             <ComboBoxItem Content="AerialWithRoads" ></ComboBoxItem>  
  20.             <ComboBoxItem Content="Terrain" ></ComboBoxItem>  
  21.          </ComboBox>  
  22.    </Grid>  
  23. </StackPanel> 

We have added light and dark as the Map Color Scheme in the MapColorBox combobox and we have added 5 Map Styles in the MapStyleBox combobox. Each of the comboboxes have a SelectionChanged event handler hooked up. Let's see how MapColorBox_SelectionChanged looks as in the following MainPage.xaml.cs:

  1. private void MapColorBox_SelectionChanged(object sender, SelectionChangedEventArgs e)  
  2. {  
  3.     if (MapColorBox!=null)  
  4.     {  
  5.         string selectedColor = ((ComboBoxItem)MapColorBox.SelectedItem).Content.ToString();  
  6.   
  7.         switch (selectedColor)  
  8.         {  
  9.             case "Light":  
  10.                 MyMap.ColorScheme = MapColorScheme.Light;  
  11.                 break;  
  12.             case "Dark":  
  13.                 MyMap.ColorScheme = MapColorScheme.Dark;  
  14.                 break;  
  15.             default:  
  16.                 MyMap.ColorScheme = MapColorScheme.Light;  
  17.                 break;  
  18.         }  
  19.     }  
  20.   

You can see that based on the SelectedItem on MapColorBox combobox we have assigned MapColorScheme of MyMap to MapColorScheme.Light or MapColorScheme.Dark.


Now, let's focus on the MapStyleBox_SelectionChanged in the MainPage.xaml.cs

  1. private void MapStyleBox_SelectionChanged(object sender, SelectionChangedEventArgs e)  
  2.         {  
  3.             if (MapStyleBox != null)  
  4.             {  
  5.                 string selectedStyle = ((ComboBoxItem)MapStyleBox.SelectedItem).Content.ToString();  
  6.   
  7.                 switch (selectedStyle)  
  8.                 {  
  9.                     case "None":  
  10.                         MyMap.Style = MapStyle.None;  
  11.                         break;  
  12.                     case "Road":  
  13.                         MyMap.Style = MapStyle.Road;  
  14.                         break;  
  15.                     case "Aerial":  
  16.                         MyMap.Style = MapStyle.Aerial;  
  17.                         break;  
  18.                     case "AerialWithRoads":  
  19.                         MyMap.Style = MapStyle.AerialWithRoads;  
  20.                         break;  
  21.                     case "Terrain":  
  22.                         MyMap.Style = MapStyle.Terrain;  
  23.                         break;  
  24.                     default:  
  25.                         MyMap.Style = MapStyle.None;  
  26.                         break;  
  27.                 }  
  28.             }  
  29.         } 

This looks like the previous one too. All we did here is based on the MapStyleBox SelectedItem we have assigned MyMap.Style to appropriate MapStyle.


Change Map Tile Source

Now usually what we see is either Bing or here Maps on the Windows Phone 8.1 Map Control. In some cases people might need to access different tile source like an Openstreet map. For those that don't understand what a tilesource is, every map system is nothing but a series of square shaped images/tiles shown for a range of geocoordinate boundaries. It's a grid of images shown based on the maps zoom level. When you zoom out or zoom in or roam around in the map, based on your X,Y and zoom level the map requests tiles of images to show you.

If you want to add/change a tiles layer, you need to change the TileSources collection of the map control. You can set the Zindex, tile pixel size and visibility. You can even forbid/allow stretching of the tiles while a higher resolution tile is being downloaded. You can define the layer type of the tile source like BackgroundReplacement, BackgroundOverlay and RoadOverlay.

Let's replace our default map tiles with Openstreetmap tiles.

  1. private void SetTileSourceToOSM()  
  2. {  
  3.    var httpsource = new HttpMapTileDataSource("http://a.tile.openstreetmap.org/{zoomlevel}/{x}/{y}.png");  
  4.    var tilesource = new MapTileSource(httpsource)  
  5.       {  
  6.          Layer = MapTileLayer.BackgroundReplacement  
  7.       };  
  8.    MyMap.Style = MapStyle.None;  
  9.    MyMap.TileSources.Add(tilesource);  

Now all we must do is call this on our OnNavigatedTo method as in the following:

  1. protected override void OnNavigatedTo(NavigationEventArgs e)  
  2. {  
  3.    SetTileSourceToOSM();  
  4.    GetMyLocation();  
  5.   

And after the app is loaded, your map will look like this. But remember as we set our layer to BackgroundReplacement we will not have any kind of map styles or other features like TrafficFlow anymore.

You will also observe the loading of the map is pretty slow since the tiles are loaded from one source. So, we can balance the load by pointing to each of three domains so the maps may load faster. All we must do is rotate the subdomain of Openstreet map between a, b and c.

  1. private void SetTileSourceToOSM()  
  2. {  
  3.    var next = "a";  
  4.    var httpsource = new HttpMapTileDataSource("http://a.tile.openstreetmap.org/{zoomlevel}/{x}/{y}.png");  
  5.   
  6.    httpsource.UriRequested += (src, args) => {  
  7.       next = GetNextDomain(next);  
  8.       args.Request.Uri = new Uri("http://" + next + ".tile.openstreetmap.org/" +  
  9.       args.ZoomLevel + "/" + args.X + "/" + args.Y + ".png");  
  10.   
  11.       };  
  12.   
  13.    var tilesource = new MapTileSource(httpsource)  
  14.    {  
  15.       Layer = MapTileLayer.BackgroundOverlay  
  16.    };  
  17.   
  18.    MyMap.Style = MapStyle.None;  
  19.    MyMap.TileSources.Add(tilesource);  
  20. }  
  21.   
  22. private string GetNextDomain(string next)  
  23. {  
  24.    string[] domains={"a""b""c"};  
  25.   
  26.    for(int count=0; count<domains.Length; count++)  
  27.    {  
  28.       if (domains[count] == next)  
  29.       return domains[(count + 1) % domains.Length];  
  30.    }  
  31.   
  32.    return next;  

Here in the GetNextDomain method you will see that all it's doing is it is actually rotating among the three subdomains of Openstreet map.

Map Events

Maps in Windows Phone 8.1 comes with much easier touch events. Touch events now comes along with GeoPoint and local UI coordinates related to the touch point. All these come along with MapTapped, MapDoubleTapped and MapHolding events. To check if a location is visible on the current map window you can use IsLocationInView().

We will try the MapTapped event for now. Select the MapControl, go over properties, go to the event handlers and double-click on the MapTapped event handler to create the method stub for that.

Now let's go ahead and write the method down:

  1. private async void MyMap_MapTapped(MapControl sender, MapInputEventArgs args)  
  2. {  
  3.    Geopoint point = new Geopoint(args.Location.Position);  
  4.   
  5.    MapLocationFinderResult FinderResult =  
  6.    await MapLocationFinder.FindLocationsAtAsync(point);  
  7.   
  8.    String format = "{0}, {1}, {2}";  
  9.   
  10.    if (FinderResult.Status == MapLocationFinderStatus.Success)  
  11.    {  
  12.       var selectedLocation=FinderResult.Locations.First();  
  13.   
  14.      string message= String.Format(format, selectedLocation.Address.Town, selectedLocation.Address.District, selectedLocation.Address.Country);  
  15.       await ShowMessage(message);  
  16.    }  
  17.   

Now here we have a sample reverse geocode query. And you can definitely see this is much easier here. You need to use the MapLocationFinder class and it has a FindLocationsAtAsync method to get back with a geocoordinate based on your tap on the map. Actually it usually returns a list and we chose the first on the list and printed out the town, district and country on a messagedialog.

You can definitely check how the thing works on the phone.

Authenticating a Maps App

The last thing that is left to do is authenticating a map app. You will see unless you provide a map control a map service AuthenticationToken it keeps asking it in the bottom of the map.

The details on that process is available here.

Our next tutorial will be on Routing, GeoFencing and Maps using MVVM.

Stay frosty!