다음을 통해 공유


UWP: How to Geocode?

Geocoding is the process of converting an address into geographical coordinates(longitutde, latitude) and reverse geocoding is, well reverse of it. It converts geographical coordinates to an address.

In this tutorial we'll learn how to convert any location/address entered by user to geographical coordinates and display a pushpin at that specified location.

To add map to your app, read my previous post.

We'll modify the UI a bit, we'll add a textbox and a button. The following code can be used to achieve this.

<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
     <TextBox Name="enterValue" PlaceholderText="Enter address/coordinates"
                FontSize="24" Margin="8" Width="300" Height="44" />
       <Button Content="Go" Click="Button_Click"></Button>
    </StackPanel>
    <Maps:MapControl
            x:Name="MapControl1"
            MapServiceToken="Token Value"
            ZoomLevel="3"
            Height="550"
            />
 </StackPanel>

 

In the click event of button, read the value entered by user and then pass it on to another function called Geocode which contains the actual logic of geo-coding. The code for the click event of button is given below.

private void  Button_Click(object sender, RoutedEventArgs e)
{
    string valueEntered = enterValue.Text;
    if (valueEntered != null || valueEntered != "")
    {
        Geocode(valueEntered);
    }
}

 

The above code simply assigns the value of the textbox to a string and before passing it as an argument to the Geocode function, makes sure that it's not empty.

private async void Geocode(string valueEntered)
{
   BasicGeoposition location = new  BasicGeoposition();
   location.Latitude = 33.6667;
   location.Longitude = 73.1667;
   Geopoint hintPoint = new  Geopoint(location);
   MapLocationFinderResult result =
      await MapLocationFinder.FindLocationsAsync(valueEntered, hintPoint);
 
   if (result.Status == MapLocationFinderStatus.Success)
   {
       BasicGeoposition newLocation = new  BasicGeoposition();
       newLocation.Latitude = result.Locations[0].Point.Position.Latitude;
       newLocation.Longitude = result.Locations[0].Point.Position.Longitude;
       Geopoint geoPoint = new  Geopoint(newLocation);
       MapAddress mapAddress = result.Locations[0].Address;
       string address = mapAddress.FormattedAddress;
       AddMapIcon(geoPoint, address);
    }
}

In the above code we have created a variable "location" of type BasicGeopostion and set it's longitude and latitude to the coordinates of Pakistan.

The reason behind setting it's coordinates to Pakistan is that this variable will be used as a hint point while geo-coding. Given my geographical location I am assuming that most of my users will be from Pakistan and that is why I have used that as a hint point. You can modify the hint point based on the geographical source of your queries.

Now let's dissect line 8-9.

MapLocationFinderResult returns the result of MapLocationFinderQuery.

MapLocationFinder is a static class that has three functions,

  1. FindLocationsAsync(string address, Geopoint referencePoint) , this function will return just one result.
  2. FindLocationsAsync(string address, Geopoint referencePoint), int maxCount), this function returns the number of maxCount result.
  3. FindLocationsAtAsync(Geopoint queryPoint), this is called reverse geo-coding.

You must have noticed the use of async and await keywords. The reason behind it is that the return type of all three functions of MapLocationFinder class is IAsyncOperation<TResult>.

The marked async method uses the await keyword, which tells the compiler that it can't move past that point until the awaited asynchronous process is complete.

Finally the value returned by FindLocationsAsync(), which is a read-only collection of elements that can be accessed by index, is stored in the variable result of type MapLocationFinderResult.

The if statement compares the status of the result query to the enum MapLocationFinderStatus and if it is successful we proceed ahead.

Finally we create a new variable called "newLocation" of type BasicGeoposition and assign it's latitude and longitude to the coordinates of Location at index 0 of list Locations. Then we assign the address of this location to another variable mapAddress of type MapAddress which can hold an address of a geographical location. To store the address in a string type variable we will simply call the read-only property FormattedAddress of MapAddress which returns the complete result in a string format.

We also created a new Geopoint variable from the newLocation variable of type BasicGeoposition using the parameterized constructor.

Now we pass geoPoint and address to another function called AddMapIcon().

private async void AddMapIcon(Geopoint geoPoint, String address)
     {
         if (mapIcon !=  null)
         {
             MapControl1.MapElements.Remove(mapIcon);
         }
         mapIcon.Location = geoPoint;
         mapIcon.Title = address;
 
         MapControl1.MapElements.Add(mapIcon);
         await MapControl1.TrySetViewAsync(geoPoint);
     }

We declared mapIcon as a class field just to make sure that there is only a single pushpin at any given time.

The above code simply removes mapIcon from the MapControl1 if it's not null. Otherwise sets it's Location and Title eto the passed parameters.

Line 10 adds the mapIcon to MapControl1 and Line 11 animates camera movement as map shifts it's center from one location to another.