For my end of study project, I am developing a windows phone 7 app with a team. We are using the geolocation features and recently needed a way for the user to select a place on the map.

Thus I made an implementation of a map picker, let’s see it.

New project
Let’s create a new project and simple change the basic grid to a map control.

New project, map instead of grid
New project, map instead of grid

[xml]
<!– /MainPage.xaml –!>

xmlns:my="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
<!– … –!>
<my:Map x:Name="MapControl" Grid.Row="1"/>
[/xml]

I also like to make some improvements to the map, let’s customize it. We also need to add a pushpin that will designate the selected place:
[xml]
<!– /MainPage.xaml –!>

<my:Map x:Name="MapControl" Grid.Row="1"
LogoVisibility="Collapsed" ScaleVisibility="Visible"
CopyrightVisibility="Collapsed" ZoomBarVisibility="Visible">
<my:Pushpin Name="Pushpin" />
</my:Map>
[/xml]

Support selection
In order to make the map tappable, I use the toolkit for windows phone 7 that you can find in codeplex: http://silverlight.codeplex.com/releases/view/55034. Don’t forget to add a reference.

You can add the tappable behavior like that:
[xml]
<!– /MainPage.xaml –!>

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
<!– … –!>
<my:Map x:Name="MapControl" Grid.Row="1"
LogoVisibility="Collapsed" ScaleVisibility="Visible"
CopyrightVisibility="Collapsed" ZoomBarVisibility="Visible">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap"/>
</toolkit:GestureService.GestureListener>
<my:Pushpin Name="Pushpin" />
</my:Map>
[/xml]

Now, you can go to the code behind. We need here to translate the screen position where the use tap and translate it to a geolocation:
[csharp]
// /MainPage.xaml.cs

private void GestureListener_Tap(object sender, GestureEventArgs e)
{
// get the tapped position relative to the map
var point = new Point(e.GetPosition(MapControl).X, e.GetPosition(MapControl).Y);
// get the geolocation of that position
var location = MapControl.ViewportPointToLocation(point);

// move the pushpin
Pushpin.Location = location;
}
[/csharp]

The thing here is that the gesture event returns the X and Y position relative to the top left of the screen. You first need to get the position relative to the map control, and then ask the map to translate it to a geolocation (longitude and latitude).
With this location you can move the pushpin to the selected place.

Selected place
Selected place

Display the selected address
Now that the user can pick a position on the map, I would like to tell him the address he selected. In order to do that we will use the Bing API located at this url: http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc/mex.

You will also need to get a Bing API key here: https://bingmapsportal.com/.

Now you can add the service reference:

Service reference
Service reference

In our code we just need to code the ReverseGeocode method on the service using the location and the API key:
[csharp]
// /MainPage.xaml.cs

private void GestureListener_Tap(object sender, GestureEventArgs e)
{
// get the tapped position relative to the map
var point = new Point(e.GetPosition(MapControl).X, e.GetPosition(MapControl).Y);
// get the geolocation of that position
var location = MapControl.ViewportPointToLocation(point);

// move the pushpin
Pushpin.Location = location;
Pushpin.Content = "loading…";

// get the address
// prepare the request
var request = new ReverseGeocodeRequest()
{
Location = location,
Credentials = new Credentials()
{
ApplicationId = "Your bing API code here"
}
};
// prepare the service
var service = new GeocodeServiceClient();
service.ReverseGeocodeCompleted += service_ReverseGeocodeCompleted;
// make the request
service.ReverseGeocodeAsync(request);
}

void service_ReverseGeocodeCompleted(object sender, ReverseGeocodeCompletedEventArgs e)
{
// if there is any address
if (e.Result.Results.Count > 0)
// use the first one
Pushpin.Content = e.Result.Results[0].Address.FormattedAddress;
// else show invalid position
else
Pushpin.Content = "Invalid";
}
[/csharp]

When the service answers our request, we can simply update the pushpin text with the address.

Address completion
Address completion

Wrap up
We just saw here how to support selection on the map control and give a fancy feedback to the user, showing a pushpin and filling the address using the Bing API. Thus we made a very nice Map Picker.

You can download the sources here : MapPicker sources.

5 thoughts on “A map picker for windows phone 7

  1. For those, who get the InvalidOperationException on the below line,

    var service = new GeocodeServiceClient();

    Try with the below code,

    GeocodeServiceClient service = new GeocodeServiceClient(new BasicHttpBinding(), new EndpointAddress(“http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc”));

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s