Current Location Tracking and Reverse Geocoding in Windows Store Apps

This article covers methods to display the user's location using GPS, the usage of Pushpins and Reverse Geocoding.

Pre-requisites: Please read my article “Maps in Windows Store Apps” before you start with this one. Download the source code provided with this article and start comparing with this article step-by-step.

Overview: This article covers methods to display the user's location using GPS, usage of Pushpins and Reverse Geocoding.

Step 1: Display the user's location using GPS.

GPS stands for Global Positioning System. It is a network of satellites in Earth's orbit that make GPS possible. It can aid in providing location and time information. We can get the location information in terms of Latitude and Longitude using GPS.

  • Adding the namespace.

Add the namespace Windows.Devices.Geolocation at the start of the application code. The statement for adding this namespace is as shown below.

  1. using Windows.Devices.Geolocation;  
This namespace has a class named Geolocator. It aids in providing access to current geographical location. 
  • Enabling capabilities to make the app workable.

Internet Client
Figure: The preceding screen shows the method to enable “Internet (Client)” and “Location” capabilities.

Click on the Package.appxmanifest file present within the project. This will result in showing the application manifest designer. Click on the Capabilities option present on the manifest designer. Check both of the “Internet (Client)” and “Location” options under Capabilities. Enabling the Location capability by checking the Location option will enable the app with the capability to get access to your current location. It helps in providing the location of the device by utilizing a dedicated sensor such as the GPS sensor present in the device. Enabling the internet (client) capability will help the app to get access to the internet and to networks in public places.

  • Utilizing the Geolocator class.

    Geolocator class diagram
    Figure: The preceding figure shows the Geolocator class diagram.

  • Let's create a scenario as follows: upon the clicking a button, the map should load the user's current location map.

Upon clicking the button Get My Location, the event handler named getCurrentLocation_Click will be called. The code snippet to get the Latitude and Longitude of the user's current location is as shown below. The GetGeopositionAsync( ) method is responsible for getting the location of the user's device. This method returns a variable of the type Geoposition class. Hence the returned value will be stored in userPos, in other words the Geoposition class variable.

  1. private async void getCurrentLocation_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.    Geolocator geoLocator=new Geolocator();  
  4.    Geoposition userPos = await geoLocator.GetGeopositionAsync();  
  5.    Location location = new Location(userPos.Coordinate.Point.Position.Latitude, userPos.Coordinate.Point.Position.Longitude);  
  6.    bingMap.Center = location;  
  7.   
  8. }  
GPS sensor
Figure: Current geolocation of the device being displayed on the map using GPS sensor.

In the preceding code the zoom level of the map is set to the value "8". We can change this zoom level to get more accuracy of the location. The current XAML code is showcased below.

ZoomLevel property
Figure: Shows the XAML code with an annotation to ZoomLevel property.

Increasing this ZoomLevel value will result in more accuracy in the location view within the map.

ZoomLevel value
Figure: Snapshot of the output after increasing the ZoomLevel value to "16".

The preceding screen clearly shows the current location map view with more accuracy, that is a result of increasing the ZoomLevel value. This is the current location view after setting the ZoomLevel property value to sixteen.

Geoposition class diagram
Figure: Geoposition class diagram.

As given in the preceding class diagram, the Geoposition class has two properties in it. One is the Coordinate property that is of type Geocoordinate class. This Geocoordinate has a property named Point that is of type Geopoint class. In turn, this GeoPoint class has a property named Position that is of type BasicGeoposition structure. BasicGeoposition structure has all the information that we need, in other words it has Altitude, Latitude and Longitude fields in it. Therefore, the flow to derive the access results is given below:

position

The CivicAddress class represents the civic address data (including City, State, Country, Postal Code) associated with the geographical location. Placing the following code in our application to display the location details (including City, State and Country) will not work in our case.

work in our case

Placing the preceding code will show the following output that is quite unusual since it renders gibberish information.

message dialog box
Figure: A message dialog box displaying incorrect current location information.

You can figure out that in the preceding screen, the city name and state name are not displayed in the message box and the country name is displayed as “US” which is an incorrect information. The expected output information is: 
  • City: Bangalore
  • State: Karnataka
  • Country: India

Remember that the GPS sensor doesn't provide civic address data/information. So, you cannot expect to get City, State, Country and Postal Code information by accessing the CivicAddress property. We can use other methods by means of utilizing classes to reverse geocode the latitude and longitude information to derive the address of the location. We can also do this using the Bing Maps Geocode Service (Bing Maps REST Services).

Step 2: Use Pushpin to point out the exact location of the user's device within the map view.

We can use the Pushpin class to represent the Pushpin on the map. A class named MapLayer can contain elements positioned on the map itself. Therefore, this will be the right choice to place a Pushpin onto the map. Where the Pushpin must be placed within the map, in other words “current location” and the “Pushpin object”, must be given as inputs to the SetPosition( ) method of the MapLayer class. This helps in setting the position of the Pushpin to the current location (in other words current latitude and longitude) within the map view. This helps in showing the Pushpin on the exact location within the map.

  1. Pushpin pushPin = new Pushpin();  
  2. MapLayer.SetPosition(pushPin, location);  
  3. bingMap.Children.Add(pushPin);  
Current location along with the Pushpin
Figure: Shows the map of the current location along with the Pushpin. 
  • Customizing the Pushpin.

Let's customize the Pushpin in such a way that it displays the latitude and longitude information about the location upon tapping the Pushpin.

  1. Add a user control page.

    Add a user control page
    Figure: Shows adding a new User Control page to the existing project.

    Right-click on the project then select “Add” and click on “New Item”. That will result in opening the “Add New Item” window. Select the User Control page option as shown in the preceding screen.

  2. Design and create a customized Pushpin look.

    For the sake of designing a customized Pushpin, I have a rectangle on which two text blocks have been placed. One text block displays the current location's latitude and the other displays the longitude.

    Design and create
    Figure: Screenshot of User Control page designer view.

    The XAML code present in the User Control page is shown below:
    1. <UserControl  
    2.     x:Class="BingMapDemo.PushinControl"  
    3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    5.     xmlns:local="using:BingMapDemo"  
    6.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
    7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    8.     mc:Ignorable="d"  
    9.     d:DesignHeight="300"  
    10.     d:DesignWidth="400">  
    11.   
    12.     <Grid Margin="0,0,125,154">  
    13.         <Rectangle Fill="#FF7B7BF3" HorizontalAlignment="Left" Height="86" Stroke="Black" VerticalAlignment="Top" Width="158"/>  
    14.         <TextBlock x:Name="txtBlkLatitude" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding}" VerticalAlignment="Top" Width="134"/>  
    15.         <TextBlock x:Name="txtBlkLongitude" HorizontalAlignment="Left" Margin="10,42,0,0" TextWrapping="Wrap" Text="{Binding}" VerticalAlignment="Top" Width="134"/>  
    16.   
    17.     </Grid>  
    18. </UserControl>  
    The Code Behind contents of the User Control page, in other words PushinControl.xaml.cs, is as shown below:
    1. namespace BingMapDemo  
    2. {  
    3.     public sealed partial class PushinControl : UserControl  
    4.     {  
    5.       
    6.         public PushinControl( string latitude, string longitude)  
    7.         {  
    8.             this.InitializeComponent();  
    9.   
    10.             txtBlkLatitude.DataContext = latitude;  
    11.             txtBlkLongitude.DataContext = longitude;  
    12.   
    13.   
    14.         }  
    15.     }  
    16. }  
    Screenshot of the code
    Figure: Screenshot of the code shows the process of creating the Pushpin tapped event and subsequent creation of an event handler for it.

    Now, I will declare both the location variable of the type Location class and the pushPinControlObj object of type PushinControl class at the class level. So that we can access both of these variables throughout the class.
    1. void pushPin_Tapped(object sender, TappedRoutedEventArgs e)  
    2. {  
    3.      try  
    4.      {  
    5.            Pushpin p = sender as Pushpin;  
    6.                 pushPinControlObj = new PushinControl("Location: "+location.Latitude.ToString(),    "Longitude: "+location.Longitude.ToString());  
    7.                 pushPinControlObj.Visibility = Visibility.Visible;  
    8.                 MapLayer.SetPosition(pushPinControlObj, location);  
    9.                 bingMap.Children.Add(pushPinControlObj);  
    10.                 bingMap.SetView(location);  
    11.      }  
    12.      catch (Exception ex)  
    13.      {               
    14.          throw ex;         
    15.  }  
    Current geolocation of the device
    Figure: Current geolocation of the device being displayed in the map along with displaying exact latitude and longitude of the device using the GPS sensor.

Step 3: Using reverse Geocoding to get the readable address.

Reverse geocoding is the process of getting the address or place details in readable format using the latitude and longitude of the location. In fact it is nothing but matching geographical coordinates to an address. We can do this by making use of the SearchManager class. This class contains the necessary methods to manage geocode and reverse geocode requests. The following piece of code helps in reverse geocoding of the current geolocation information to get the readable address of the current location.

  1. ReverseGeocodeRequestOptions reverseGeoCode = new ReverseGeocodeRequestOptions(location);  
  2. SearchManager searchTheLocation = bingMap.SearchManager;  
  3. LocationDataResponse locationResponse= await searchTheLocation.ReverseGeocodeAsync(reverseGeoCode);  
  4. MessageDialog msg=new MessageDialog(locationResponse.LocationData[0].Address.FormattedAddress.ToString());  
  5. await msg.ShowAsync( );  
With respect to the preceding code, the location is the variable of type Location class. This location variable stores the current location of the device. For the sake of defining reverse geocoding request options we use the ReverseGeocodeRequestOptions class. The variable of type Location class must be passed as a parameter to the ReverseGeocodeRequestOptions class's constructor during object creation. Getting the search manager of the current map and storing it in a separate object of type SearchManager class is done in the program by issuing the following statement:
  1. SearchManager searchTheLocation = bingMap.SearchManager;  
Here bingMap is the name of the Bing Map control specified in the XAML code of this application. Since bingMap is the current map, we need to access the SearchManager of this map and should store it in another variable. Here, an object of type LocationDataResponse class is used to store the response to a reverse geocoding request. In fact, this LocationDataResponse class is used to store a response to a geocoding request or reverse geocoding request.

LocationDataResponse
Figure: Class diagram of LocationDataResponse.

The ReverseGeocodeAsync( ) method present in the SearchManager class takes an object of the ReverseGeocodeRequestOptions class as input and returns LocationDataResponse. This LocationDataResponse in turn has a LocationData property of type GeocodeLocationCollection that is a collection of GeocodeLocation objects. The GeocodeLocation class has an Address variable of the type GeocodeAddress class.

GeocodeAddress class diagram
Figure: GeocodeAddress class diagram.

The GeocodeAddress class contains three properties. All are of data type "string". We need to access the Address variable to access all the preceding properties in this case. The Address gets the postal address of the geolocation. The FormattedAddress property fetches the string containing the complete address. In a similar way Landmark fetches the landmark associated with an address. Neighborhood fetches the neighborhood associated with an address.

Output screen with a message dialog box
Figure: Output screen with a message dialog box showing formatted address obtained using reverse geocoding.

According to the preceding screen, “Raja Rajeshwari Nagar, Bengaluru, 560098, India” is the formatted address of the current location.

Since this GeocodeAddress class is inherited from the MapAddress class, we need to understand the properties of the MapAddress class that can be utilized further since the GeocodeAddress class inherits properties of MapAddress by default.

Class diagram of MapAddress class
Figure: Class diagram of MapAddress class.

The AddressLine string property helps in getting the official street line of an address. The Subdivision name in the region/country of an address can be retrieved by accessing the AdminDistrict string property. If there is another level of subdivision within the first subdivision then it can be accessed using the AdminDistrict2 property. CountryRegion gets the country or region name of an address. The PostalCode string property can help us in getting the postal code/PIN code/Zip code of the region with respect to the address.

Now, let's change the location and run the app to test the app.

Output screen with message dialog box
Figure: Output screen with message dialog box showing formatted address after changing the location.

Let's display the address information including Address line, District, State, Country and PIN code of the current address. The output of the application is as shown below:

Output screen with a message
Figure: Output screen with a message dialog box showing the Address line, District, State, Country and PIN code of the current address.