April 2017

Volume 32 Number 4

[Modern Apps]

Exploring the Map Control

By Frank La

Frank La VigneMaps are truly one of mobile devices’ great features. With a smartphone in hand, you can expertly navigate your way through a new city, find all the great places to eat, get real-time updates to traffic conditions, even find a new route—if a faster one is available. Mapping can also help your users visualize data points or provide a quick search of local services.

Maps have truly changed the way users interact with their devices and their world. Fortunately, the Universal Windows Platform (UWP) comes equipped with a fully functional Map control that leverages the power and imagery of Bing’s mapping services. In this month’s column, I’ll explore Map control and show just how easy it is to add to your apps.

Setting Up the Project

Create a new blank UWP project in Visual Studio by choosing New Project from the File menu. Expand the Installed Templates | Windows | Blank App (Universal Windows). Name the project MapControl and then click OK. Immediately afterward, a dialog box will appear asking you which version of Windows the app should target. For this project, the default options will be fine, so you can just click OK.

Open the MainPage.xaml file and add the following namespace declaration to the Page tag:

xmlns:maps="using:Windows.UI.Xaml.Controls.Maps"

This makes the elements located in the Windows.UI.Xaml.Controls.Maps namespace addressable to the XAML elements contained in the Page control by using the maps: prefix. For a detailed explanation of XAML Namespaces and Namespace Mapping, Windows Dev Center has an in-depth article on the matter at bit.ly/2jwcO2D.

Adding the Map Control

To add a map to this app, simply add the following XAML:

<maps:MapControl x:Name="mapControl" >
  </maps:MapControl>

Run the solution by pressing F5 or choosing Start Debugging from the Debug menu. Your app should look something like Figure 1. Note that you can click and drag around the map to navigate it. Double-clicking will zoom in on a point. Additionally, touch gestures also manipulate the Map control. You’ll also notice red text in the lower-left corner of the control stating, “Warning: MapServiceToken not specified.”

Basic Map Control
Figure 1 Basic Map Control

The Map control uses imagery and other services, such as traffic data, from Bing Maps. Accordingly, the Bing team would like to have the ability to audit which accounts drive usage. This helps limit abuse and keep costs low for everyone. To remove the warning message, you’ll need to obtain a MapServiceToken from the Bing Maps Dev Center. In most instances, usage of Bing Maps services will be free. For pricing details, refer to the pricing chart for Basic and Enterprise keys at microsoft.com/maps/create-a-bing-maps-key.aspx

Registering for a Bing Maps Service Token

In a browser, go to bingmapsportal.com, click sign in, and use your Microsoft account credentials to log in. On the landing page, click the My account menu and choose My Keys, as shown in Figure 2.

Accessing My Keys on the Bing Maps Dev Center
Figure 2 Accessing My Keys on the Bing Maps Dev Center

If you’ve registered keys with Bing Maps before, then they’ll appear in a list, as shown in Figure 3. To create a new key, click on the option that states “Click here to create a new key.”

My Keys Page with Listing of Previously Registered Keys
Figure 3 My Keys Page with Listing of Previously Registered Keys

A form will appear asking for information about the application for which the key will be created (see Figure 4). Name the app, choose Basic for Key type, and Universal Windows App for Application type. The Application URL is optional. Click create and you’ll be presented with a new key. Copy it and return to the MainPage.xaml file. Modify the XAML to add the MapServiceToken attribute and paste in the key as its value, like so:

<maps:MapControl x:Name="mapControl" MapServiceToken="{Insert Key Here}" >
  </maps:MapControl>

Create Key Form
Figure 4 Create Key Form

Run the solution again and the warning message is gone.

Controlling the Map with Code

As you can see, adding a Map control to a UWP app is fairly easy. The control even comes with the ability for users to manipulate the map’s center point and zoom level with mouse or touch. The map would be more useful if it could be manipulated in code. For instance, it would be useful to change the style of the map, so that it can display aerial imagery or terrain data and not just the default road view shown in Figure 1.

Changing Map Styles

The Map control has a Style property of type MapStyle, which is an enumeration. For example, to change the map to show aerial imagery with roads superimposed on them, all it takes is this line of code:

mapControl.Style = MapStyle.AerialWithRoads;

To implement the option of choosing any available MapStyle, the app will need some more controls. Add the following Grid definitions to the Grid on the Page control in the MainPage.xaml file to create some space for the controls you’re about to add:

<Grid.RowDefinitions>
  <RowDefinition Height="50*"/>
  <RowDefinition Height="50*"/>
  <RowDefinition Height="577*"/>
</Grid.RowDefinitions>

Next, add the Grid.Row attribute to the Map control and set its value to 2.

Now, add the following Button controls in a StackPanel:

<StackPanel Orientation="Horizontal" Grid.Row="0">
  <Button Content="Roads" Click="Button_Click" Margin="3" />
  <Button Content="Aerial" Click="Button_Click" Margin="3" />
  <Button Content="Aerial With Roads" Click="Button_Click" Margin="3"/>
  <Button Content="Terrain" Click="Button_Click" Margin="3" />
  <Button Content="3D Aerial" Click="Button_Click" Margin="3" />
  <Button Content="3D Aerial With Roads" Click="Button_Click" Margin="3"/>
</StackPanel>

In the MainPage.xaml.cs file, add the event handler code in Figure 5 to determine which button was clicked and then set the map to the appropriate style.

Figure 5 Event Handler Code

private void Button_Click(object sender, RoutedEventArgs e)
  {
    var senderButton = sender as Button;
    var buttonTest = senderButton.Content.ToString();
    switch (buttonTest)
    {
      case "Aerial":
      mapControl.Style = MapStyle.Aerial;
      break;
    case "Aerial With Roads":
    mapControl.Style = MapStyle.AerialWithRoads;
    break;
    case "Terrain":
      mapControl.Style = MapStyle.Terrain;
      break;
    case "3D Aerial":
      mapControl.Style = MapStyle.Aerial3D;
      break;
    case "3D Aerial With Roads":
      mapControl.Style = MapStyle.Aerial3DWithRoads;
      break;
    default:
    mapControl.Style = MapStyle.Road;
    break;
  }
}

Run the app now and explore the map using the different styles available. Also note that when using one of the 3D views that the control, once again, handles all mouse and touch functions automatically.

Zooming In and Out

By default, the map will be fully zoomed out, providing a view of the entire Earth. That might not be useful for a lot of purposes. The Map control has a property of type Double called ZoomLevel to set how far zoomed in or out the map will appear. The value ranges from 1 to 20, with 1 being zoomed in all the way and 20 showing the entire world. Values outside this range are ignored.

Adding zoom in and zoom out to the app is quite easy. First, add the following XAML elements to the MainPage.xaml file inside the Grid control:

<StackPanel Orientation="Horizontal" Grid.Row="1">
  <Button x:Name="btnZoomIn" Content="Zoom In" Click="btnZoomIn_Click"
    Margin="3" />
  <Button x:Name="btnZoomOut" Content="Zoom Out" Click="btnZoomOut_Click"
    Margin="3" />
</StackPanel>

Next, add the following two event handlers for the two buttons:

private void btnZoomIn_Click(object sender, RoutedEventArgs e)
{
  mapControl.ZoomLevel = mapControl.ZoomLevel + 1;
}
private void btnZoomOut_Click(object sender, RoutedEventArgs e)
{
  mapControl.ZoomLevel = mapControl.ZoomLevel - 1;
}

Placing Markers on Maps

Another useful feature of mapping software is the ability to place markers on various points of interest. This could be a great way to point out local attractions. The Map control makes this easy, as well. For this example, place a marker on the Washington Monument in Washington, D.C. The Washington Monument’s geospatial coordinates are 38.8895 north and 77.0353 west. To do this, add the following code to the MainPage.xaml.cs file:

private void LoadMapMarkers()
{
  MapIcon landmarkMapIcon = new MapIcon();
  landmarkMapIcon.Location = new Geopoint(
    new BasicGeoposition() { Latitude = 38.8895, Longitude = -77.0353 } );
  landmarkMapIcon.Title = "Washington Monument";
  mapControl.MapElements.Add(landmarkMapIcon);
}

Next, call the function from the MainPage constructor method.

Run the app now and you’ll see a marker has been placed on the map in Washington, D.C., exactly where the Washington Monument sits.

Latitude and Longitude

All points on Earth can be represented by a coordinate system that measures the angular distance from the equator and the Prime Meridian in Greenwich, England. Degrees latitude measures north and south in degrees from -90 at the South Pole to 90 at the North Pole. Degrees longitude measures east or west in degrees from -180 to 180.

Viewing Traffic Data

Bing tracks traffic flow data from cities around the world and the Map control can overlay this data onto a map very easily. To add this feature to the app, add the following markup to the MainPage.xaml file right after the Zoom Out button:

<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"
  Margin="3">Show Traffic</CheckBox>

Then add the following event handlers to the MainPage.xaml.cs file:

private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
  mapControl.TrafficFlowVisible = true;
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
  mapControl.TrafficFlowVisible = false;
}

Run the app, check the Show Traffic CheckBox, and zoom into any major city. Traffic data will only be displayed when the zoom level is at 8 or greater.

Geolocation

Now the app has several controls to change the style of the map, zoom in or out, and even display traffic flow data. It would be helpful for the map control to initialize near the user’s current location. That way, users can quickly get a view of their local surroundings, as well as traffic conditions nearby. To do this, you’ll need to enable the Location capability in the Package.appxmanifest file, as shown in Figure 6. In Visual Studio, double-click on the Package.appxmanifest file in the Solution Explorer pane. In the editor, make sure the checkbox next to Location is checked. Save the file. Now, the app has the Location Capability.

Enabling the Location Capability for the App
Figure 6 Enabling the Location Capability for the App

In the MainPage.xaml file add the following Button control:

<Button x:Name="btnCurrentLocation" Content="Current Location"
  Click="btnCurrentLocation_Click" Margin="3"/>

And add the following event handler in the MainPage.xaml.cs file:

private async void btnCurrentLocation_Click(object sender, RoutedEventArgs e)
{
  var locationAccessStatus = await Geolocator.RequestAccessAsync();
  if (locationAccessStatus == GeolocationAccessStatus.Allowed)
  {
    Geolocator geolocator = new Geolocator();
    Geoposition currentPosition = await geolocator.GetGeopositionAsync();
    mapControl.Center = new Geopoint(new BasicGeoposition()
    {
      Latitude = currentPosition.Coordinate.Latitude,
      Longitude = currentPosition.Coordinate.Longitude
    });
    mapControl.ZoomLevel = 12;
  }
}

The btnCurrentLocation_Click method first queries the GeoLocator object for what the access status the app has to it. Upon the first time the app runs on the user’s system, the system will display a dialog box similar to the one shown in Figure 7. If the user clicks on Yes, the code gets the current position from the Geolocator. Afterward, the code centers the map on the latitude and longitude provided. If the Location capability hasn’t been added, the user wouldn’t have even been prompted with the dialog.

Asking the User for Permission to Access Precise Location Information
Figure 7 Asking the User for Permission to Access Precise Location Information

Run the app now, click on the Current Location button, click on Yes if prompted. You should see the map focus in on, or very near, your current location. Accuracy will depend on a number of factors. If your device is connected to a GPS receiver, then your accuracy will be very high—likely down to around 10 meters. If your device lacks a GPS receiver, the Geo­Locator relies on other means to determine location, such as using Wi-Fi. For more information on how Wi-Fi positioning works, refer to the Wikipedia entry at en.wikipedia.org/wiki/Wi-Fi_positioning_system. If Wi-Fi is unavailable, the GeoLocator will use the client device’s IP address to determine location, where VPN connections and other factors can significantly lower accuracy.

Wrapping Up

Maps are truly one of the more essential features of mobile devices. Many apps could benefit from the addition of a Map control to visualize data or assist users in finding nearby services. In this column, you saw just how easy it is to add a map to your application and that, in most cases, access to the mapping services comes at no cost to you, the developer.


Frank La Vigne is an independent consultant, where he helps customers leverage technology in order to create a better community. He blogs regularly at FranksWorld.com and has a YouTube channel called Frank’s World TV (FranksWorld.TV).

Thanks to the following technical experts for reviewing this article: Rachel Appel


Discuss this article in the MSDN Magazine forum