Universal Windows Platform - Map Control

In this article you will learn about Universal Windows Platform Map Control.

Introduction

In new update of Universal Windows Platform, there are significant APIs changed from previous Windows Phone 8.0 & 8.1. A lots of great features added like Geofencing. So let’s get crack in a whole new Universal Windows Platform Map Control.

Creating a New Project and Add a Map Control

Take a new project and give it a name simply “Map” or whatever you want. Now, we’ll add our map control from the “Toolbox”. Drag the “MapContol” tool from the “Toolbox” and place it in the main Grid.

MapContol
                            Figure 1

Making Grids

Now, we’ll modify our main Grid to re-size the “MapControl” and to show some other stuffs. Firstly, we’ll make some rows to put other control.

  1. <Grid.RowDefinitions>  
  2.     <RowDefinition Height="50"/>  
  3.     <RowDefinition Height="*"/>  
  4. </Grid.RowDefinitions>  
Listing 1

There are two “RowDefinitions”. First one is 50px in height, other is “*” which will cover the rest of the grid space.

Adding Controls

Here are the controls we’ve used in our “MainPage.xaml”.
  1. <TextBlock TextWrapping="NoWrap" Grid.Row="0"  
  2.             Text="Map control"  
  3.             FontSize="36" />  
  4.   
  5. <Maps:MapControl Grid.Row="1"  
  6.     x:Name="MyMap"  
  7.     HorizontalAlignment="Stretch"  
  8.     VerticalAlignment="Stretch"  
  9.     Width="360"  
  10.     Height="590" ZoomLevelChanged="MyMap_ZoomLevelChanged"/>  
  11.   
  12. <Border CornerRadius="10" x:Name="border" Grid.Row="1"  
  13.         Height="70"  
  14.         Width="70"  
  15.         Canvas.Left="150"  
  16.         Canvas.Top="270"  
  17.         Background="{ThemeResource AppBarItemPointerOverBackgroundThemeBrush}">  
  18.     <ProgressRing x:Name="progressRing"  
  19.                         IsActive="True"  
  20.                         Background="Transparent"  
  21.                         Height="40"  
  22.                         Width="40"/>  
  23. </Border>  
  24.   
  25. <Slider Grid.Row="1" x:Name="mySlider" Orientation="Vertical" HorizontalAlignment="Right" Height="211" Width="45" Margin="0,0,10,0" Minimum="10" Maximum="20" Value="0" ValueChanged="ZoomValueChanged" Foreground="SteelBlue"/>  
Listing 2

We’ve used a “ProgressBar” control, to indicate while Map is loading, a “TextBlock” to show the title, a “MapControl” to show the Bing Map and a “Slider” to zoom in and zoom out.

Adding AppBar

We’ve also used a “BottomAppBar” to locate your current position.
  1. <Page.BottomAppBar>  
  2.     <CommandBar ClosedDisplayMode="Minimal" Opacity="0.5">  
  3.         <AppBarButton Label="locate me" Icon="Target" Click="LocateMe_Click" />  
  4.     </CommandBar>  
  5. </Page.BottomAppBar>  
Listing 3

I’m not going through the details of adding controls and how they work, if you don’t know please feel free to take a look at my previous articles.

So, finally our design will look like the following screenshot:

design
                     Figure 2

Code Behind

Now, time to code behind in C#. Let’s open “MainPage.xaml.cs” and find “OnNavigatedTo” method. Modify it like the following:
  1. public sealed partial class MainPage : Page  
  2. {  
  3.     Geolocator geolocator;  
  4.   
  5.     public MainPage()  
  6.     {  
  7.  this.InitializeComponent();  
  8.  this.Loaded += MainPage_Loaded;  
  9.     }  
  10.   
  11.     private async void MainPage_Loaded(object sender, RoutedEventArgs e)  
  12.     {  
  13.         // Map Token for testing purpose,   
  14.         // otherwise you'll get an alart message in Map Control  
  15.         MyMap.MapServiceToken = "abcdef-abcdefghijklmno";  
  16.    
  17.         geolocator = new Geolocator();  
  18.         geolocator.DesiredAccuracyInMeters = 50;  
  19.    
  20.         try  
  21.         {  
  22.             // Getting Current Location  
  23.             Geoposition geoposition = await geolocator.GetGeopositionAsync(  
  24.                 maximumAge: TimeSpan.FromMinutes(5),  
  25.                 timeout: TimeSpan.FromSeconds(10));  
  26.    
  27.             MapIcon mapIcon = new MapIcon();  
  28.             // Locate your MapIcon  
  29.             mapIcon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/my-position.png"));  
  30.             // Show above the MapIcon  
  31.             mapIcon.Title = "Current Location";  
  32.             // Setting up MapIcon location  
  33.             mapIcon.Location = new Geopoint(new BasicGeoposition()  
  34.             {  
  35.                 //Latitude = geoposition.Coordinate.Latitude, [Don't use]  
  36.                 //Longitude = geoposition.Coordinate.Longitude [Don't use]  
  37.                 Latitude = geoposition.Coordinate.Point.Position.Latitude,  
  38.                 Longitude = geoposition.Coordinate.Point.Position.Longitude  
  39.             });  
  40.             // Positon of the MapIcon  
  41.             mapIcon.NormalizedAnchorPoint = new Point(0.5, 0.5);  
  42.             MyMap.MapElements.Add(mapIcon);  
  43.             // Showing in the Map  
  44.             await MyMap.TrySetViewAsync(mapIcon.Location, 18D, 0, 0, MapAnimationKind.Bow);  
  45.                
  46.             // Disable the ProgreesBar  
  47.             progressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;  
  48.             // Set the Zoom Level of the Slider Control  
  49.             mySlider.Value = MyMap.ZoomLevel;  
  50.         }  
  51.         catch (UnauthorizedAccessException)  
  52.         {  
  53.             MessageBox("Location service is turned off!");  
  54.         }  
  55.         base.OnNavigatedTo(e);  
  56.     }  
  57. ...  
  58. }  
Listing 4

Our main work is done, now we’ve to write the other methods to work it perfectly.
  1. // Slider Control  
  2. private void ZoomValueChanged(object sender, RangeBaseValueChangedEventArgs e)  
  3. {  
  4.     if (MyMap != null)  
  5.         MyMap.ZoomLevel = e.NewValue;  
  6. }  
  7.   
  8. private void MyMap_ZoomLevelChanged(MapControl sender, object args)  
  9. {  
  10.     if (MyMap != null)  
  11.         mySlider.Value = sender.ZoomLevel;  
  12. }  
  13.   
  14. // Locate Me Bottom App Bar  
  15. private async void LocateMe_Click(object sender, RoutedEventArgs e)  
  16. {  
  17.     progressBar.Visibility = Windows.UI.Xaml.Visibility.Visible;  
  18.     geolocator = new Geolocator();  
  19.     geolocator.DesiredAccuracyInMeters = 50;  
  20.   
  21.     try  
  22.     {  
  23.         Geoposition geoposition = await geolocator.GetGeopositionAsync(  
  24.             maximumAge: TimeSpan.FromMinutes(5),  
  25.             timeout: TimeSpan.FromSeconds(10));  
  26.         await MyMap.TrySetViewAsync(geoposition.Coordinate.Point, 18D);  
  27.         mySlider.Value = MyMap.ZoomLevel;  
  28.         progressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;  
  29.     }  
  30.     catch (UnauthorizedAccessException)  
  31.     {  
  32.         MessageBox("Location service is turned off!");  
  33.     }  
  34. }  
  35.   
  36. // Custom Message Dialog Box  
  37. private async void MessageBox(string message)  
  38. {  
  39.     var dialog = new MessageDialog(message.ToString());  
  40.     await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await dialog.ShowAsync());  
  41. }  
Listing 5

Adding Tap Event

One more thing, I’d like to add is Map Tapped functionality, we’ll add another method which will give us a cool feature when we tap somewhere and in the Map Icon. It’ll show the location details in the Message Dialog Box.

To add this method, go to “MainPage.xaml”, select “MapControl” in the main grid. If you don’t see “Properties” tab, then hit F4 and you’ll find it on the left side of the Visual Studio.

Now double click on the “MapTapped” section and it’ll automatically generate the method stub for you.

Properties
                                          Figure 3

Now, complete the “MyMap_MapTapped” method in the “MainPage.xaml.cs”.
  1. private async void MyMap_MapTapped(MapControl sender, MapInputEventArgs args)  
  2. {  
  3.     Geopoint pointToReverseGeocode = new Geopoint(args.Location.Position);  
  4.     // Reverse geocode the specified geographic location.  
  5.     MapLocationFinderResult result = await MapLocationFinder.FindLocationsAtAsync(pointToReverseGeocode);  
  6.     var resultText = new StringBuilder();  
  7.     if (result.Status == MapLocationFinderStatus.Success)  
  8.     {  
  9.         resultText.AppendLine(result.Locations[0].Address.District + ", " + result.Locations[0].Address.Town + ", " + result.Locations[0].Address.Country);  
  10.     }  
  11.     MessageBox(resultText.ToString());  
  12. }  
Listing 6

Adding Location Capability

Now, our work is done, but if you run the application in your device or emulator, you’ll get an error definitely. Because we’ve given permission to track our current position to our application. To do this, go to “Package.appxmanifest” and find “Capabilities” section and tick the “Location” service and save it.

Capabilities
                           Figure 4

Running the Application

Now if you run the application it’ll look exactly like the following screenshot:

run application
                                             Figure 5

If you tap on the “MapIcon” it’ll show the location details on the Message Dialog Box.

MapIcon
                                             Figure 6

Using Polygon for Pushpin

Another thing, if don’t want to use external image as a “MapIcon”, you can use custom “Pushpin” like “Polygon” control. Then you’ve to modify the “OnNavigatedTo” method like the following code snippet:
  1. private async void MainPage_Loaded(object sender, RoutedEventArgs e)  
  2. {  
  3.     // Map Token for testing purpose,   
  4.     // otherwise you'll get an alart message in Map Control  
  5.     MyMap.MapServiceToken = "abcdef-abcdefghijklmno";  
  6.     geolocator = new Geolocator();  
  7.     geolocator.DesiredAccuracyInMeters = 50;  
  8.     try  
  9.     {  
  10.         // Getting Current Location  
  11.         Geoposition geoposition = await geolocator.GetGeopositionAsync(maximumAge: TimeSpan.FromMinutes(5), timeout: TimeSpan.FromSeconds(10));  
  12.         // Create a New Pushpin  
  13.         var pushpin = CreatePushPin();  
  14.         MyMap.Children.Add(pushpin);  
  15.         // Setting up Pushpin location  
  16.         var location = new Geopoint(new BasicGeoposition()  
  17.         {  
  18.             Latitude = geoposition.Coordinate.Latitude,  
  19.                 Longitude = geoposition.Coordinate.Longitude  
  20.         });  
  21.         MapControl.SetLocation(pushpin, location);  
  22.         // Position of the Pushpin  
  23.         MapControl.SetNormalizedAnchorPoint(pushpin, new Point(0.0, 1.0));  
  24.         // Showing in the Map  
  25.         await MyMap.TrySetViewAsync(location, 18 D, 0, 0, MapAnimationKind.Bow);  
  26.         // Disable the ProgressBar  
  27.         progressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;  
  28.         // Set the Zoom Level of the Slider Control  
  29.         mySlider.Value = MyMap.ZoomLevel;  
  30.     }  
  31.     catch (UnauthorizedAccessException)  
  32.     {  
  33.         MessageBox("Location service is turned off!");  
  34.     }  
  35.     base.OnNavigatedTo(e);  
  36. }  
Listing 7

And “CreatePushPin” method is given below.
  1. private DependencyObject CreatePushPin()  
  2. {  
  3.     // Creating a Polygon Marker  
  4.     Polygon polygon = new Polygon();  
  5.     polygon.Points.Add(new Point(0, 0));  
  6.     polygon.Points.Add(new Point(0, 50));  
  7.     polygon.Points.Add(new Point(25, 0));  
  8.     polygon.Fill = new SolidColorBrush(Colors.Red);  
  9.     // Return the Polygon Marker  
  10.     return polygon;  
  11. }  
Listing 8

Running the Application

Now, if you run the application, the marker will look like this.

marker
                                                Figure 7

Peach Heading

One more thing I’d like to add is Pitch heading. To do this, you need to simply paste the following code in MainPage_Loaded method, under the try-catch block.
  1. private async void MainPage_Loaded(object sender, RoutedEventArgs e)  
  2. {...  
  3.     MapScene spaceNeedleScene = MapScene.CreateFromLocationAndRadius(mapIcon.Location, 400, /* show this many meters around */ 135, /* looking at it to the south east*/ 60 /* degrees pitch */ );  
  4. }  
  5. catch ()  
  6. {}  
  7. }  
Listing 9

And if your run the application, it will give you much different view from angle of sixty degrees.

run the application
                                             Figure 8

Map Overlaying

One more thing I’d like to add is overlaying tiled images on a map. If you want to overlay third-party or custom tiled images on the map and make it customized, then you simply need to use the following lines of code in the “MainPage_Loaded” method at the top.

 

  1. private async void MainPage_Loaded(object sender, RoutedEventArgs e)  
  2. {  
  3.     ...  
  4.     var httpsource = new HttpMapTileDataSource("http://a.tile.openstreetmap.org/{zoomlevel}/{x}/{y}.png");  
  5.     var ts = new MapTileSource(httpsource);  
  6.     MyMap.TileSources.Add(ts);...  
  7. }  
Listing 10

And if your run the application, it will provide you a much more graphical view than before with some details.

Map Control
                              Figure 9

Summary

And that’s it! Hope you understood, how to use “MapControl” in Universal Windows Platform. Have fun with Map Control and make some cool applications with it. Read more about Maps and directions at – GitHub.

Happy Coding!

You can download the full source code, here.