I created a small test application to get the Longitude and Latitude and to convert it to the actual address:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Device.Location;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Services;
using Microsoft.Phone.Shell;
using PhoneApp1.Resources;
using Windows.Devices.Geolocation;
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
private GeoCoordinate Location;
public ObservableCollection<string> Addresses { get; set; }
// Constructor
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
protected override async void OnNavigatedTo( NavigationEventArgs e )
{
await GetLocation();
}
public async Task GetLocation()
{
Location = await CoordinateConverter.GetLocation();
ReverseGeoCoding.StartReverseGeoCoding( Location );
//ReverseGeoCoding.done.WaitOne();
string Address = ReverseGeoCoding.Address;
}
}
public static class ReverseGeoCoding
{
public static ObservableCollection<string> Addresses = new ObservableCollection< string >();
public static string Address;
public static bool Completed;
public static AutoResetEvent done = new AutoResetEvent( true );
public static void StartReverseGeoCoding( GeoCoordinate Location )
{
Completed = false;
var reverseGeocode = new ReverseGeocodeQuery();
reverseGeocode.GeoCoordinate = new GeoCoordinate( Location.Latitude, Location.Longitude );
reverseGeocode.QueryCompleted += ReverseGeocodeQueryCompleted;
done.Reset();
reverseGeocode.QueryAsync();
}
public static void ReverseGeocodeQueryCompleted( object sender, QueryCompletedEventArgs<System.Collections.Generic.IList<MapLocation>> e )
{
var reverseGeocode = sender as ReverseGeocodeQuery;
if ( reverseGeocode != null )
{
reverseGeocode.QueryCompleted -= ReverseGeocodeQueryCompleted;
}
//Microsoft.Phone.Maps.Services.MapAddress address;
Addresses.Clear();
if ( !e.Cancelled )
{
foreach ( var address in e.Result.Select( adrInfo => adrInfo.Information.Address ) )
{
Addresses.Add( string.Format( "{0} {1}, {2} {3} {4}, {5}",
address.HouseNumber,
address.Street,
address.City,
address.State,
address.PostalCode,
address.Country ).Trim() );
}
}
if ( Addresses.Count > 0 )
{
Address = Addresses[ 0 ].ToString();
}
else
{
Address = "";
}
done.Set();
Completed = true;
}
}
public static class CoordinateConverter
{
public static GeoCoordinate ConvertGeocoordinate( Geocoordinate geocoordinate )
{
return new GeoCoordinate
(
geocoordinate.Latitude,
geocoordinate.Longitude,
geocoordinate.Altitude ?? Double.NaN,
geocoordinate.Accuracy,
geocoordinate.AltitudeAccuracy ?? Double.NaN,
geocoordinate.Speed ?? Double.NaN,
geocoordinate.Heading ?? Double.NaN
);
}
public static async Task<GeoCoordinate> GetLocation()
{
// Get current location.
Geolocator myGeolocator = new Geolocator();
myGeolocator.DesiredAccuracy = PositionAccuracy.High;
//myGeolocator.DesiredAccuracyInMeters = 50;
Geocoordinate myGeocoordinate = null;
try
{
Geoposition myGeoposition = await myGeolocator.GetGeopositionAsync
(
maximumAge: TimeSpan.FromMinutes( 1 ),
timeout: TimeSpan.FromSeconds( 10 )
);
myGeocoordinate = myGeoposition.Coordinate;
}
catch ( Exception ex )
{
if ( (uint)ex.HResult == 0x80004004 )
{
// the application does not have the right capability or the location master switch is off
MessageBox.Show( "location is disabled in phone settings" );
}
}
if ( myGeocoordinate == null )
{
return GeoCoordinate.Unknown;
}
GeoCoordinate myGeoCoordinate = CoordinateConverter.ConvertGeocoordinate( myGeocoordinate );
return myGeoCoordinate;
}
}
}
The code works fine, i.e. the ReverseGeocodeQueryCompleted is called and the address is being calculated properly. However, ReverseGeocodeQueryCompleted occurs after GetLocation() is completed and the address assigned to Address is null.
My question is how to make
ReverseGeoCoding.StartReverseGeoCoding( Location );
wait for the completion of:
ReverseGeocodeQueryCompleted( object sender, QueryCompletedEventArgs<System.Collections.Generic.IList<MapLocation>> e )
{
....
}
I tried with AutoResetEvent
and WaitOne
, but the whole thread stops and the code never gets to ReverseGeocodeQueryCompleted()
.
I am open to suggestions how to solve this problem.
EitanB
Here is an extension method to be Able to await QueryAsync:
I modified a bit Benoit's answer to look like this:
this will replace the following two functions in my code:
endif
Overall works fine, and again thanks to Benoit!
Look for
TaskCompletionSource
for task synchronization.I'll write a better response later. Meanwhile, take a look at Bringing async/await to the Contacts service on the Nokia Developer Wiki.