1. Problem
At application startup,
you want to localize by position of the phone to see where in the world
is and what is the relative address.
2. Solution
The solution to this
problem is very simple if you use classes available in Windows Phone 7.
However, the official solution is unusable at this time, because CivicAddressResolver was scheduled to be included in Silverlight for Windows Phone, and using CivicAddressResolver you can disclose to obtain a CivicAddress by using the geo-coordinates. This method has not yet been implemented.
However, in this section, we
will show you what to do, so when the method is implemented, you will be
ready to integrate features that can use it. Meanwhile, we will show
you an alternative implementation of this service.
3. How It Works
Retrieving the user's position on the map based on geo-coordinates will
be simple. You will use certain classes in the namespace associated with
the civic System.Device.Location to retrieve coordinates that we are providing.
4. The Code
As you can see in Figure 1, the CivicAddressResolver class implements the ICivicAddressResolver
interface. Therefore, even if the service is not implemented yet, you
might think the realization of our resolver, rather than wait for
subsequent implementations, just as you will do shortly. But let's
proceed step by step.
First, declare at the class level these two members:
GeoCoordinateWatcher geoWatcher = null;
ICivicAddressResolver civicResolver = null;
Next, create two private void methods dedicated to initialize the preceding members:
InitWatcher()
InitResolver()
The names that we choosen is self-explaining, says us all that you will do in their implementation, that you can see below
private void InitResolver()
{
//for now we will use the default implementation
civicResolver = new CivicAddressResolver();
civicResolver.ResolveAddressCompleted += new
EventHandler<ResolveAddressCompletedEventArgs>(civicResolver_ResolveAddressCompleted);
}
private void InitWatcher()
{
geoWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
geoWatcher.PositionChanged += new
EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(geoWatcher_PositionChanged);
geoWatcher.StatusChanged += new
EventHandler<GeoPositionStatusChangedEventArgs>(geoWatcher_StatusChanged);
geoWatcher.Start();
}
The use of InitWatcher is clear, because you have seen it in previous recipes. InitResolver indicates that the class CivicAddressResolver will make a call to some external service, and will raise the OnResolveAddressCompleted event when it has finished finding the information you need.
void geoWatcher_PositionChanged(object sender,
GeoPositionChangedEventArgs<GeoCoordinate> e)
{
var civic = civicResolver.ResolveAddress(e.Position.Location);
}
void civicResolver_ResolveAddressCompleted(object sender,
ResolveAddressCompletedEventArgs e)
{
//do something with resolved address
//here you can see the properties that you can access
//e.Address.AddressLine1
//e.Address.AddressLine2
//e.Address.Building
//e.Address.City
//e.Address.CountryRegion
//e.Address.FloorLevel
//e.Address.PostalCode
//e.Address.StateProvince
}
This is all you need to do to use CivicAddressResolver.
It's simple to use this class, but is also useless because behind of
this class there is no implementation. Therefore, we have given you a
way to implement a service similar to what Microsoft has planned, but
"homemade."
You will need to use a Bing Maps service from http://msdn.microsoft.com/en-us/library/cc966738.aspx and then add a service reference to the Geocode Service.
First, add a new class to your project and call it CustomCivicResolver:
public class CustomAddressResolver : ICivicAddressResolver
{
public CivicAddress ResolveAddress(GeoCoordinate coordinate)
{
//...
}
public void ResolveAddressAsync(GeoCoordinate coordinate)
{
//...
}
public event EventHandler<ResolveAddressCompletedEventArgs> ResolveAddressCompleted;
{
...
}
You will implement only ResolveAddressAsync, simply because you are using Silverlight for Windows phone and so are not interested in the synchronous pattern.
You declare at the global class level the proxy for the service:
GeocodeService.GeocodeServiceClient proxy = null;
And you must write the constructor of the class, where you will instantiate the proxy and subscribe to the event OnReverseGeocodeCompleted:
public CustomAddressResolver()
{
proxy = new GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
proxy.ReverseGeocodeCompleted += new
EventHandler<GeocodeService.ReverseGeocodeCompletedEventArgs>(
proxy_ReverseGeocodeCompleted);
}
Then it's time to prepare your
request to the service (and prepare your service to respond to the
request that will come from the outside):
public void ResolveAddressAsync(GeoCoordinate coordinate)
{
proxy.ReverseGeocodeAsync(
new GeocodeService.ReverseGeocodeRequest()
{
Location = new Microsoft.Phone.Controls.Maps.Platform.Location()
{
Latitude = coordinate.Latitude,
Longitude = coordinate.Longitude,
Altitude = coordinate.Altitude
},
Credentials = new Microsoft.Phone.Controls.Maps.Credentials()
{
ApplicationId = "Put you app key here"
});
}
The only row of this code that
must be commented is the creation of a credential for the service. You
must get an API key for your application from http://msdn.microsoft.com/en-us/library/cc966738.aspx. Without this key, you will never have a response from the service. So remember to do this before you carry on.
void proxy_ReverseGeocodeCompleted(object sender,
GeocodeService.ReverseGeocodeCompletedEventArgs e)
{
ResolveAddressCompleted(
sender,
new ResolveAddressCompletedEventArgs(
new CivicAddress()
{
AddressLine1 = e.Result.Results[0].Address.AddressLine,
AddressLine2 = e.Result.Results[0].Address.FormattedAddress,
Building = "",
City = e.Result.Results[0].Address.Locality,
CountryRegion = e.Result.Results[0].Address.CountryRegion,
FloorLevel = "0",
PostalCode = e.Result.Results[0].Address.PostalCode,
StateProvince = e.Result.Results[0].Address.PostalTown
},
e.Error,
e.Cancelled,
e.UserState));
}
When the ReverseGeocodeCompleted fires, you also fire the event ResolveAddressCompleted, member of the ICivicAddressResolver interface, that will be triggered by who uses this class.
As you can see, you can't add some information in CivicAddress, such as Building and FloorLevel,
but if you aren't writing an application to track the position of a
courier, we think you can do well without this information (and it is
still better than not having the ability to retrieve information).
5. Usage
From Visual Studio 2010,
start the application. Wait for your position to become available and
then look for retrieved addresses while you move around the globe.
Remember, in order to use Position in your application, you must
activate it in the settings or you will never have correct information
to work from.