Make Clickable Shapes in the Native Bing Maps Control

The native Bing Maps Windows Store control has two types of shapes: polygons and polylines. These shapes are great for representing areas and paths on the map. Often it is useful to be able to associate some information or metadata with these shapes. In past versions of Bing Maps we could easily store this information in the Tag property of the shape. This makes it easy to retrieve this data when a shape is clicked or tapped. Unfortunately,the MapPolygon and MapPolyline shapes in the native Bing Maps Windows Store control do not have a Tag property. Recently on the Bing Maps forums, one of our Bing Maps engineers pointed out that the MapPolygon and MapPolyline classes are both DependancyObjects. This means that we could create a DependencyProperty which adds a “Tag” property to these shapes. In this blog post we are going to see just how easy this is to do.

To get started, open up Visual Studio and create a new project in either C# or Visual Basic. Select the Blank App template, call the application ClickableShapes, and press OK.

Add a reference to the Bing Maps SDK. To do this, right click on the References folder and press Add Reference. Select Windows -> Extensions, and then select Bing Maps for C#, C++ and Visual Basic and Microsoft Visual C++ Runtime. If you do not see this option ensure that you have installed the Bing Maps SDK for Windows Store apps.

 

If you notice that there is a little yellow indicator on the references that you just added. The reason for this is that the C++ runtime package requires you to set the Active solution platform in Visual Studio to one of the following options; ARM, x86 or x64. To do this, right click on the Solution folder and select Properties. Then go to Configuration Properties -> Configuration. Find your project and under the Platform column set the target platform to x86. Press OK and the yellow indicator should disappear from our references.

Next open the MainPage.xaml file and update it with the following XAML. This will add a map to the app. Make sure to set the Credentials attribute of the Map element to a valid Bing Maps key.

<Page
    x:Class="ClickableShapes.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ClickableShapes"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:m="using:Bing.Maps"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <m:Map Name="MyMap" Credentials="YOUR_BING_MAPS_KEY"/>
    </Grid>
</Page>

Both the MapPolygon and MapPolyline classes derive from a common class called MapShape. Rather than creating two DependencyProperty's, we can instead create a single one on the MapShape class. Open the MainPage.xamls.cs or MainPage.xaml.vb file and update it with the following code. This will create a DependencyProperty on the MapShape class called “Tag”.

C#

using Bing.Maps;
using System;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace ClickableShapes
{
    public sealed partial class MainPage : Page
    {
        private MapShapeLayer shapeLayer;

        public static readonly DependencyProperty TagProp = DependencyProperty.Register("Tag", typeof(object), typeof(MapShape),new PropertyMetadata(null));

        public MainPage()
        {
            this.InitializeComponent();
        }
    }
}

Visual Basic

Imports Bing.Maps
Imports Windows.UI
Imports Windows.UI.Popups

Public NotInheritable Class MainPage
    Inherits Page

    Private shapeLayer As MapShapeLayer

    Public Shared ReadOnly TagProp As DependencyProperty = DependencyProperty.Register("Tag", GetType(Object), GetType(MapShape), New PropertyMetadata(Nothing))

    Public Sub New()
        Me.InitializeComponent()
    End Sub
End Class

Next we will add an event handler for when the map is loaded in the constructor of the app. In this event handler we will add a MapShapeLayer to the map for loading our shapes to. We will then generate a test polygon and polyline to the map. We will add some string as metadata to the Tag property by using the SetValue method on the shape. Update the constructor and add the MyMapLoaded event handler to the MainPage.xamls.cs or MainPage.xaml.vb file using the following code.

C#

public MainPage()
{
    this.InitializeComponent();

    MyMap.Loaded += MyMapLoaded;
}

private void MyMapLoaded(object sender, RoutedEventArgs e)
{
    //Add a shape layer to the map
    shapeLayer = new MapShapeLayer();
    MyMap.ShapeLayers.Add(shapeLayer);

    //Create mock data points
    var locs = new LocationCollection();

    locs.Add(new Location(0, 0));
    locs.Add(new Location(10, 10));
    locs.Add(new Location(10, 0));

    //Create test polygon
    var polygon = new MapPolygon();
    polygon.Locations = locs;
    polygon.FillColor = Colors.Red;

    //Set the tag property value
    polygon.SetValue(TagProp, "I'm a polygon");

    //Add a tapped event
    polygon.Tapped += ShapeTapped;

    //Add the shape to the map
    shapeLayer.Shapes.Add(polygon);

    var locs2 = new LocationCollection();
    locs2.Add(new Location(20, 20));
    locs2.Add(new Location(40, 40));
    locs2.Add(new Location(50, 20));

    //Create test polyline
    var polyline = new MapPolyline();
    polyline.Locations = locs2;
    polyline.Width = 5;
    polyline.Color = Colors.Blue;

    //Set the tag property value
    polyline.SetValue(TagProp, "I'm a polyline");

    //Add a tapped event
    polyline.Tapped += ShapeTapped;

    //Add the shape to the map
    shapeLayer.Shapes.Add(polyline);
}

Visual Basic

Private Sub MyMapLoaded(sender As Object, e As RoutedEventArgs)
    'Add a shape layer to the map
    shapeLayer = New MapShapeLayer()
    MyMap.ShapeLayers.Add(shapeLayer)

    'Create mock data points
    Dim locs = New LocationCollection()

    locs.Add(New Location(0, 0))
    locs.Add(New Location(10, 10))
    locs.Add(New Location(10, 0))

    'Create test polygon
    Dim polygon = New MapPolygon()
    polygon.Locations = locs
    polygon.FillColor = Colors.Red

    'Set the tag property value
    polygon.SetValue(TagProp, "I'm a polygon")

    'Add a tapped event
    AddHandler polygon.Tapped, AddressOf ShapeTapped

    'Add the shape to the map
    shapeLayer.Shapes.Add(polygon)

    Dim locs2 = New LocationCollection()
    locs2.Add(New Location(20, 20))
    locs2.Add(New Location(40, 40))
    locs2.Add(New Location(50, 20))

    'Create test polyline
    Dim polyline = New MapPolyline()
    polyline.Locations = locs2
    polyline.Width = 5
    polyline.Color = Colors.Blue

    'Set the tag property value
    polyline.SetValue(TagProp, "I'm a polyline")

    'Add a tapped event
    AddHandler polyline.Tapped, AddressOf ShapeTapped

    'Add the shape to the map
    shapeLayer.Shapes.Add(polyline)
End Sub

Finally we will need to create the event handler for when the shapes are tapped. When a shape is tapped we will be able to use the GetView method on the shape to retrieve the Tag property. We will then take this value and display it to the user using a MessageDialog. Add the following event handler to the MainPage.xamls.cs or MainPage.xaml.vb file.

C#

private async void ShapeTapped(object sender, TappedRoutedEventArgs e)
{
    if (sender is MapShape)
    {
        var poly = sender as MapShape;
        var tag = poly.GetValue(TagProp);

        if (tag != null && tag is string)
        {
            var msg = new MessageDialog(tag as string);
            await msg.ShowAsync();
        }
    }
}

Visual Basic

Private Async Sub ShapeTapped(sender As Object, e As TappedRoutedEventArgs)
    If TypeOf sender Is MapShape Then
        Dim poly = TryCast(sender, MapShape)
        Dim tag = poly.GetValue(TagProp)

        If tag IsNot Nothing AndAlso TypeOf tag Is String Then
            Dim msg = New MessageDialog(TryCast(tag, String))
            Await msg.ShowAsync()
        End If
    End If
End Sub

The application is now complete. Deploy the app by pressing F5 or clicking on the Debug button. When the app is running tap or click on the shapes on the map. When the event is fired a message will be displayed that contains the metadata stored in the Tag property of the shape.

Note in this example I simply stored a string in the Tag property, but you can store any object you want in it. You can download the full source code for this code sample from the Visual Studio code gallery here.

If you are looking for some other great resources on Bing Maps for Windows Store apps, look through the Bing Developer Center blog or check out all the Bing Maps MSDN code samples.

- Ricky Brundritt, EMEA Bing Maps TSP

FinalApp-ClickableShapes-Thumbnail.png