Blog

Building Location-Aware Apps for Your Surface RT

Microsoft’s Surface RT lacks a GPS receiver (bummer!), but you can still use WinRT’s location API to build location-aware apps for it. As long as you have a WiFi connection, the location API can determine where you are with a reasonable degree of accuracy – sometimes with astonishing accuracy – using WiFi positioning. Furthermore, you can combine the location API with the Bing Maps control available in the Bing Maps SDK for Windows Store Apps to present location data in a rich and informative way.

To demonstrate, I built a simple app that 1) retrieves the user’s current location, 2) shows that location on a map, and 3) shows the address of any location on the map that the user taps. Addresses are determined by feeding a latitude and longitude into Bing Maps’ reverse-geocoding service. Here’s what the app looked like when I started it up in the basement of my home:

And here’s how it looked when I zoomed across the country and tapped Building 37 on the Microsoft campus:

What does it take to write an app like this? Remarkably little. You begin by downloading and installing the Bing Maps SDK for Windows Store Apps on your development machine.  Then, in a Visual Studio Windows Store project, you use the Add Reference command to add a reference to Bing Maps and the Microsoft Visual C++ Runtime Package:.

Next, you go into Configuration Manager (you’ll find it in the Build menu), set Active Solution Platform to the platform you’re running Visual Studio on, which is probably x64. You can’t, unfortunately, use “Any CPU” as you normally would in a C# project because the Bing Maps SDK relies on unmanaged code:

Finally, open the app manifest and check the Location box on the Capabilities page. This is essential because an app that uses the location API must indicate as much in its manifest:

Now you’re ready to start adding code. Open MainPage.xaml and replace the empty Grid in the body of the page with this:

<Page.Resources>
    <x:String x:Key="Credentials">Insert key here</x:String>
</Page.Resources>

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" xmlns:maps="using:Bing.Maps">
    <maps:Map x:Name="BingMap" Credentials="{StaticResource Credentials}" MapType="Aerial" Tapped="OnMapTapped">
        <maps:Map.Children>
            <maps:Pushpin x:Name="Pin" Width="50" Height="50">
                <maps:Pushpin.Template>
                    <ControlTemplate>
                        <Grid>
                            <Ellipse Width="50" Height="50" Fill="Red" />
                            <Ellipse Width="40" Height="40" Fill="White" />
                            <Ellipse Width="30" Height="30" Fill="Red" />
                            <Ellipse Width="20" Height="20" Fill="White" />
                            <Ellipse Width="10" Height="10" Fill="Red" />
                        </Grid>
                    </ControlTemplate>
                </maps:Pushpin.Template>
            </maps:Pushpin>
        </maps:Map.Children>
    </maps:Map>
</Grid>

Before you go any further, replace “Insert key here” in the string resource named “Credentials” with your Bing Maps API key. If you don’t have a Bing Maps API key, you can get one by going to the Bing Maps Account Center and requesting one. It’s fast and it’s free.

The next step is to open MainPage.xaml.cs and replace the OnNavigatedTo method with the following methods:

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    // Get the current location
    var locator = new Geolocator();
    var position = await locator.GetGeopositionAsync();

    // Center the map on the current location
    var location = new Location(position.Coordinate.Latitude, position.Coordinate.Longitude);
    BingMap.SetView(location, 18.0); // Zoom level == 18

    // Show the current position with a pushpin
    MapLayer.SetPosition(Pin, location);
}

private async void OnMapTapped(object sender, TappedRoutedEventArgs e)
{
    // Get the position of the tap
    var map = (Map)sender;
    var pos = e.GetPosition(map);

    // Convert the position into a map location
    Location location;
    map.TryPixelToLocation(pos, out location);

    // Convert the map location into an address
    var Client = new HttpClient();
    var result = await Client.GetStringAsync(string.Format("http://dev.virtualearth.net/REST/v1/Locations/{0},{1}?o=xml&key={2}", location.Latitude.ToString(CultureInfo.InvariantCulture), location.Longitude.ToString(CultureInfo.InvariantCulture), this.Resources["Credentials"]));

    var doc = XDocument.Parse(result);
    var address = doc.Descendants().Elements().Where(n => n.Name.LocalName == "FormattedAddress").FirstOrDefault();

    if (address != null)
        await new MessageDialog(address.Value).ShowAsync();
    else
        await new MessageDialog("Address not available").ShowAsync();
}

Now test the project on your local machine to make sure you haven’t made any mistakes. If it builds and runs OK, you’re ready for the final step: building an ARM package and deploying it to your Surface.

Due to a bug in the current release of the Bing Maps SDK – a bug that will be fixed soon – a debug build of an app that uses Bing Maps will crash the moment it starts up on an ARM device such as a Surface RT. Therefore, you need to generate an ARM package containing a release build of the app and deploy the package manually. Generating the package is no more difficult than using the Project –> Store –> Create App Packages command to start the Create App Packages wizard and specifying the type of package you want:

Once the package is generated, copy it to a USB stick, walk the USB stick over to your Surface and plug it in, and run the PowerShell script named Add-AppDevPackage.ps1, which you’ll find among the package files. Once that’s done, you can start the app from its tile on the start screen.

Jeff Prosise

View Comments

  • Hello, I'm slightly confused by this article. Is the Bing Maps control needed to detect the user's location? Or is the Bing Maps control only for displaying the user's location?
    The reason I'm asking is because I already have the code you showed above:
    var locator = new Geolocator();
    var position = await locator.GetGeopositionAsync();
    However, on a Surface RT, I don't get a location. Is there something the Bing Maps control does behind the scenes that I'm not aware of?
    Thank you!

  • The location API gives you the user's location, and the Bing Maps control displays that location. The map doesn't have any ability on its own to determine the user's location.
    The Surface RT lacks GPS and cellular hardware, so the only place location data can come from is WiFi Positioning. Therefore, you have to have a network connection for the location API to work. If GetGeopositionAsync is returning no data, then either 1) you don't have a connection, or 2) the router you're connected to isn't mapped in Microsoft's WiFi Positioning database.

  • Hi Mr. Prosise, thank you for your response. I tend to think there is something that isn't being communicated from MS.
    I do my dev on a laptop, which lacks GPS and cellular hardware. My app does a decent job of identifiying my location. However, when I try to run the app on a Surface RT, hitting the same router, I get no data.
    This is unfortunate. Your article is accurate. Its just frustrating trying to get an app work properly on Windows anymore. They should have kept moving forward with Silverlight and made that their common UI platform.

  • Does GetGeopositionAsync return null? Does it return anything? Try checking the LocationStatus property to see what's going on. I'm wondering if it's saying PositionStatus.Disabled.

  • Thank you sooooooo much for this valuable information, I have been pulling my hair out for the past couple of hours trying to figure out why Bing maps is not working on my app when I deploy to surface, setting the ARM package to release fixed it.

Recent Posts

How to Navigate Azure Governance

 Cloud management is difficult to do manually, especially if you work with multiple cloud…

4 days ago

Why Azure’s Scalability is Your Key to Business Growth & Efficiency

Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…

3 weeks ago

Unlocking the Power of AI in your Software Development Life Cycle (SDLC)

https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…

1 month ago

The Role of FinOps in Accelerating Business Innovation

FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…

1 month ago

Azure Kubernetes Security Best Practices

Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…

1 month ago

Mastering Compliance: The Definitive Guide to Managed Compliance Services

In the intricate landscape of modern business, compliance is both a cornerstone of operational integrity…

2 months ago