Udostępnij za pośrednictwem


How to Share Maps Using the Share Charm in Windows Store Apps

Depending on the type of application you are creating, you may find it useful to be able to share a map with someone. Whether it’s a map of a single location or a map with a route on it, this can easily be accomplished in a Windows Store app. In this blog post we are going to take a look at two different ways you can share a map in a Windows Store app.

Sharing things is easy in Windows Store apps when using the Share charm. We can easily specify text or HTML that we want to share inside a message. There are two ways we can do share a map. The first is to use the Bing Maps REST Imagery service and generate an image of a map. The second method is to make use of the Bing Maps consumer site (https://bing.com/maps) and build a URL.

Creating a Map Image

The Bing Maps REST Imagery service makes it easy to generate an image of map. There are several different options and parameters that can be used to generate static map images. Here is one of the most basic structures for generating a static map image.

https://dev.virtualearth.net/REST/v1/Imagery/Map/ [ImagerySet] / [CenterPoint] / [ZoomLevel] ? [ImageOptionParameters]& key= [BingMapsKey]

The ImagerySet parameter can have one of the following values:

clip_image002

clip_image004

clip_image006

Aerial

AerialWithLabels

Road

clip_image008

clip_image010

OrdnanceSurvey (UK only)

CollinsBart (London UK only)

The CenterPoint value of the URL is used to center the map over a specific coordinate. This consists of the latitude and longitude values being separated by a comma. The ZoomLevel is an integer value between 1 and 19 that indicates the level at which the map image should zoom. The following are some of the image option parameters that can be used with the Imagery API.

Parameter

Description

declutterPins

Specifies whether to change the display of overlapping pushpins so that they display separately on a map. (Optional)

1: Declutter pushpin icons.

0: Do not declutter pushpin icons. (default)

format

The image format to use for the static map. By default the best file format for a particular map style is used. (Optional)

gif: GIF image format.

jpeg: JPEG image format. JPEG format is the default for Road, Aerial and AerialWithLabels imagery.

png: PNG image format. PNG is the default format for CollinsBart and OrdnanceSurvey imagery.

mapArea

The geographic area to display on the map. Required when a center point or set of route points are not specified. This is a comma separated set of numbers using the following format:

“South Latitude,West Longitude,North Latitude,East Longitude”

mapLayer

A display layer that renders on top of the imagery set. The only value for this parameter is TrafficFlow. (Optional)

Example: mapLayer=TrafficFlow

mapSize

A string that contains a width and a height separated by a comma. The width must be between 80 and 900 pixels and the height must be between 80 and 834 pixels. The default map size for static maps is 350 pixels by 350 pixels. (Optional)

pushpin

A series of values that include a Point value (latitude and longitude) with options to add a label of up to three (3) characters and to specify an icon style. You can specify up to 18 pushpins within a URL and 100 if you use the HTTP POST method and specify the pushpins in the body of the request. (Optional)

A short form version of this parameter is available: pp

There are many other parameters available that can be used to add routes as well. You can find full documentation on Bing Maps REST Imagery service on MSDN.

One nice thing about REST services is that they are very easy to test. Once you have created a REST request URL you can simply put it in the address bar of a browser to see the response.

Using this information we can create the following URL that opens an image of Bing Maps with the map centered on a specific location (Seattle - 47.60356,-122.32943) with a zoom level of 12, and the map view set to the road map view:

https://dev.virtualearth.net/REST/V1/Imagery/Map/Road/47.60356,-122.32943/12?key=YOUR\_BING\_MAPS\_KEY

Here is the generated image:

clip_image011

Creating a URL to Bing Maps

The Bing Maps consumer site exposes a number of URL query parameters which can be used to load a custom map view. These parameters are very similar to the Bing Maps REST Imagery service. You can customize the URL to display specific search results, driving directions, or items in your “My Places” folder.

To create a URL to the Bing Maps consumer site, start with the base URL and then use parameters to specify the location and options such as zoom level, map view, search panels, and more. The base address you should use is https://bing.com/maps/default.aspx. The following is a list of some of the basic parameters you can use:

Parameter

Description

cp

Defines where the center of the map should be. Use the following format for the cp parameter: Latitude~Longitude

lvl

Defines the zoom level of the map. Valid values are 1-19. This parameter is ignored if you don't include the cp parameter.

style

Defines the map view. Valid values for this parameter include:

a: Display an aerial view of the map.

r: Display a road view of the map.

h: Display an aerial view of the map with labels.

o: Use this value to display a bird's eye (oblique) view of the map.

b: Display a bird's eye (oblique) with labels view of the map.

u: Automatic

trfc

Specifies whether traffic information is included on the map. Omitting the trfc parameter produces the same results as trfc=0.

You can find full documentation on creating URLs for the Bing Maps consumer site on the Bing Help website.

Using this information we can create the following URL that opens Bing Maps with the map centered on a specific location (Seattle - 47.60356,-122.32943) with a zoom level of 12, and the map view set to the road map view: https://bing.com/maps/default.aspx?cp=47.60356~-122.32943&lvl=12&style=r

Opening this URL in a browser will load up the Bing Maps consumer site centered over Seattle.

clip_image013

Sharing from a Windows Store App

Now that we understand the basics of generating a static map image and a link to the Bing Maps consumer site, we can use this to create a Windows Store app that allows us to share this information through the Share charm. For this app we will create a simple application that uses the Bing Maps Windows Store control. When the Share charm is activated it will use the center point and zoom level of the map to generate the map image and URL to the Bing Maps consumer site. In addition to this, we will also add a button to the app that will launch the share charm. You may find this useful in the future if you have a list of results and you want to let the user select a single result and share it all with a single touch.

To get started let’s open up Visual Studios and create a new project in your preferred language: JavaScript, C# or Visual Basic. Select the Blank App template and call the application BingMapsShareCharm and press OK.

clip_image015

Add a reference to the Bing Maps SDK. To do this, right click on the References folder and press Add Reference. Select Windows -> Extensions select Bing Maps for C#, C++ and Visual Basic or Bing Maps for JavaScript. If you do not see this option ensure that you have installed the Bing Maps SDK for Windows Store apps. While you are here, if using C# or Visual Basic, add a reference to the Microsoft Visual C++ Runtime Package as this is required by the Bing Maps SDK.

clip_image017

If you are using C# or Visual Basic you may notice that there is a little yellow indicator on the references that you just added. The reason for this is that in the C++ runtime package you have 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. For this blog post I’m going to select x86. Press Ok and the yellow indicator should disappear from our references.

clip_image019

If you are using JavaScript right click on the js folder and select Add -> New Item. Create a new JavaScript file called ShareMap.js. We will put all our JavaScript for this application in there to keep things clean. Now open up the default.html file and update the HTML to the following:

 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BingMapsShareCharm</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- BingMapsShareCharm references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>

    <!-- Bing Map Control references -->
    <script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

    <!-- Our Bing Maps JavaScript Code -->
    <script src="/js/ShareMap.js"></script>
</head>
<body>
    <div id="MyMap"></div>
    <button id="ShareBtn" style="position:absolute;top:0;left:400px;background-color:#000;">Share Location</button>
</body>
</html>

If you are using C# or Visual Basic open the MainPage.xaml file and add update the xaml to the following:

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

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <m:Map Name="MyMap" Credentials="YOUR_BING_MAPS_KEY"/>
        
        <StackPanel Margin="10" Height="40" VerticalAlignment="Top" HorizontalAlignment="Center" Background="Black">
            <Button Content="Share Location" Tapped="ShareLocation_Tapped"/>
        </StackPanel>
    </Grid>
</Page>

Be sure to add your Bing Maps key into the XAML.

Next we can add the functionality to power the application. Regardless of the language you are using you will have to do the following tasks:

1. Get a reference to the Share charm for the current view using the DataTransferManager.

2. Add an event handler when the user navigates to the app that is fired when data is requests by the Share charm. Remove this event handler when the user leaves the app.

3. Since we are using Bing Maps generate a session key from the map after the map has loaded. A session key is a special Bing Maps key that marks requests to the REST services as non-billable.

4. When a custom share button is tapped show the UI for the Share charm.

5. Create an event handler for when the Share charm is launched. To share an image through the share charm, generate some HTML with the layout you prefer. Add an img tag for where you want the image to go and provide it with a temporary URL. You can then load the image as a stream to the request and specify the temporary URL the image is meant for. In the HTML you can also add an anchor tag that links to the Bing Maps consumer site with the same map, but interactive.

If you are using JavaScript you have one more task and that is to load the Bing Maps control.

If you are using C# open the MainPage.xaml.cs file and update the code to the following:

 using System;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;

namespace BingMapsShareCharm
{
    public sealed partial class MainPage : Page
    {
        /// <summary>
        /// A reference to the DataTransferManager for the Share charm.
        /// </summary>
        private DataTransferManager dataTransferManager;

        private string sessionKey;

        public MainPage()
        {
            this.InitializeComponent();

            //Get the DataTransferManager object associated with current window 
            dataTransferManager = DataTransferManager.GetForCurrentView();

            MyMap.Loaded += MyMap_Loaded;            
        }

        private async void MyMap_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            sessionKey = await MyMap.GetSessionIdAsync();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            //Register the share handler event
            dataTransferManager.DataRequested += ShareHandler;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            //Unregister the share handler event
            dataTransferManager.DataRequested -= ShareHandler;
        }

        private void ShareLocation_Tapped(object sender, TappedRoutedEventArgs e)
        {
            //Show the charm bar with Share option opened
            DataTransferManager.ShowShareUI();
        }

        private void ShareHandler(DataTransferManager sender, DataRequestedEventArgs e)
        {
            //A temporary image URL that is used for referencing the created map image.
            string localImage = "ms-appx:///images/map.png";

            //Use the Bing Maps REST Services to retrieve a static map image of the selected location.
            string mapImageUrl = string.Format("https://dev.virtualearth.net/REST/v1/Imagery/Map/Road/{0:N5},{1:N5}/{2}?mapSize=400,300&key={3}",
                MyMap.Center.Latitude, MyMap.Center.Longitude, Math.Round(MyMap.ZoomLevel), sessionKey);

            //Create URL to the Bing Maps consumer site
            string bingMapsUrl = string.Format("https://bing.com/maps/default.aspx?v=2&cp={0:N5}~{1:N5}&lvl={2}",
                MyMap.Center.Latitude, MyMap.Center.Longitude, Math.Round(MyMap.ZoomLevel));

            //Handle the Share Charm request and insert HTML content.
            DataRequest request = e.Request;
            request.Data.Properties.Title = "Share Map";
            request.Data.Properties.Description = "Share an image of the current map.";

            request.Data.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat(
                string.Format("Map of: {0:N5}, {1:N5}<br/><br/><img src='{2}'/><br/><a href='{3}'>View on Bing Maps</a>",
                    MyMap.Center.Latitude, MyMap.Center.Longitude, localImage, bingMapsUrl)));

            //Load the map image into the email as a stream.
            RandomAccessStreamReference streamRef = RandomAccessStreamReference.CreateFromUri(new Uri(mapImageUrl));
            request.Data.ResourceMap[localImage] = streamRef;
        }
    }
}

If you are using Visual Basic open the MainPage.xaml.vb file and update the code to the following:

 Imports Windows.ApplicationModel.DataTransfer
Imports Windows.Storage.Streams
Imports Windows.UI.Xaml.Controls
Imports Windows.UI.Xaml.Input
Imports Windows.UI.Xaml.Navigation

Partial Public NotInheritable Class MainPage
    Inherits Page
    ''' <summary>
    ''' A reference to the DataTransferManager for the Share charm.
    ''' </summary>
    Private dataTransferManager As DataTransferManager

    Private sessionKey As String

    Public Sub New()
        Me.InitializeComponent()

        'Get the DataTransferManager object associated with current window 
        dataTransferManager = dataTransferManager.GetForCurrentView()

        AddHandler MyMap.Loaded, AddressOf MyMap_Loaded
    End Sub

    Protected Async Sub MyMap_Loaded(sender As Object, e As Windows.UI.Xaml.RoutedEventArgs)
        sessionKey = Await MyMap.GetSessionIdAsync()
    End Sub

    Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
        'Register the share handler event
        AddHandler dataTransferManager.DataRequested, AddressOf ShareHandler
    End Sub

    Protected Overrides Sub OnNavigatedFrom(e As NavigationEventArgs)
        'Unregister the share handler event
        RemoveHandler dataTransferManager.DataRequested, AddressOf ShareHandler
    End Sub

    Private Sub ShareLocation_Tapped(sender As Object, e As TappedRoutedEventArgs)
        'Show the charm bar with Share option opened
        dataTransferManager.ShowShareUI()
    End Sub

    Private Sub ShareHandler(sender As DataTransferManager, e As DataRequestedEventArgs)
        'A temporary image URL that is used for referencing the created map image.
        Dim localImage As String = "ms-appx:///images/map.png"

        'Use the Bing Maps REST Services to retrieve a static map image of the selected location.
        Dim mapImageUrl As String = String.Format("https://dev.virtualearth.net/REST/v1/Imagery/Map/Road/{0:N5},{1:N5}/{2}?mapSize=400,300&key={3}", MyMap.Center.Latitude, MyMap.Center.Longitude, Math.Round(MyMap.ZoomLevel), sessionKey)

        'Create URL to the Bing Maps consumer site
        Dim bingMapsUrl As String = String.Format("https://bing.com/maps/default.aspx?v=2&cp={0:N5}~{1:N5}&lvl={2}",
                MyMap.Center.Latitude, MyMap.Center.Longitude, Math.Round(MyMap.ZoomLevel))

        'Handle the Share Charm request and insert HTML content.
        Dim request As DataRequest = e.Request
        request.Data.Properties.Title = "Share Map"
        request.Data.Properties.Description = "Share an image of the current map."

        request.Data.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat(String.Format("Map of: {0:N5}, {1:N5}<br/><br/><img src='{2}'/><br/><a href='{3}'>View on Bing Maps</a>",
            MyMap.Center.Latitude, MyMap.Center.Longitude, localImage, bingMapsUrl)))

        'Load the map image into the email as a stream.
        Dim streamRef As RandomAccessStreamReference = RandomAccessStreamReference.CreateFromUri(New Uri(mapImageUrl))
        request.Data.ResourceMap(localImage) = streamRef
    End Sub
End Class

If you are using JavaScript open the ShareMap.js file and update the code to the following:

 (function () {
    var app = WinJS.Application;
    var map, sessionKey, dataTransferManager;

    app.onready = function (args) {
        //Get the DataTransferManager object associated with current window 
        dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

        //Register the share handler event
        dataTransferManager.addEventListener("datarequested", ShareHandler);
    };

    app.onunload = function (args) {
        //Unregister the share handler event
        dataTransferManager.removeEventListener("datarequested", ShareHandler);
    };

    function initialize() {
        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });

        document.getElementById("ShareBtn").addEventListener("click", function (e) {
            Windows.ApplicationModel.DataTransfer.DataTransferManager.showShareUI();
        }, true);
    }

    function GetMap() {
        map = new Microsoft.Maps.Map(document.getElementById("MyMap"), {
            credentials: "YOUR_BING_MAPS_KEY"
        });

        map.getCredentials(function(c){
            sessionKey = c;
        });
    }

    function ShareHandler(e){
        var mapCenter = map.getCenter();
        var lat = Math.round(mapCenter.latitude * 100000) / 100000;
        var lon = Math.round(mapCenter.longitude * 100000) / 100000;

        //A temporary image URL that is used for referencing the created map image.
        var localImage = "ms-appx:///images/map.png";
                
        //Use the Bing Maps REST Services to retrieve a static map image.
        var mapImageUrl = 'https://dev.virtualearth.net/REST/v1/Imagery/Map/Road/' + lat + ',' + lon + '/' + map.getZoom() + '?mapSize=400,300&key=' + sessionKey;
        
        //Create URL to the Bing Maps consumer site
        var bingMapsUrl = 'https://bing.com/maps/default.aspx?v=2&cp=' + lat + '~' + lon + '&lvl=' + map.getZoom();

        //Handle the Share Charm request and insert HTML content.
        var request = e.request;
        request.data.properties.title = 'Share Map';
        request.data.properties.description = 'Share an image of the current map.';

        var html = "Map of: " + lat + ", " + lon + "<br/><br/><img src='" + localImage + "'/><br/><a href='" +  + "'>View on Bing Maps</a>";
        request.data.setHtmlFormat(Windows.ApplicationModel.DataTransfer.HtmlFormatHelper.createHtmlFormat(html));

        //Load the map image into the email as a stream.
        var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri(mapImageUrl));
        request.data.resourceMap[localImage] = streamRef;
    }       

    document.addEventListener("DOMContentLoaded", initialize, false);
})();

Be sure to add your Bing Maps key into the GetMap method.

Now run your application, and zoom in to a location. Press the custom share button you created or the Share charm button and select the Mail option. You should end up with an email with a map in it. Here is a screenshot of the app:

clip_image021

I have made the full source code for all the languages available on the visual Studio galleries here.

Comments