I developing windows phone 8 application
I need to get the user current location city and state name on page load (Application start)
I tryed with following code
public SplashPage()
{
InitializeComponent();
GetCurrentCoordinate();
}
private async void GetCurrentCoordinate()
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10));
_accuracy = currentPosition.Coordinate.Accuracy;
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);
if (MyReverseGeocodeQuery == null || !MyReverseGeocodeQuery.IsBusy)
{
MyReverseGeocodeQuery = new ReverseGeocodeQuery();
MyReverseGeocodeQuery.GeoCoordinate = new GeoCoordinate(MyCoordinate.Latitude, MyCoordinate.Longitude);
MyReverseGeocodeQuery.QueryCompleted += MyReverseGeocodeQuery_QueryCompleted;
MyReverseGeocodeQuery.QueryAsync();
}
}
catch (Exception ex)
{
}
}
private void MyReverseGeocodeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<Microsoft.Phone.Maps.Services.MapLocation>> e)
{
if (e.Error == null)
{
if (e.Result.Count > 0)
{
MapAddress address = e.Result[0].Information.Address;
CurrentLocTextBlock.Text = "Current Location: " + address.City + ", " + address.State;
}
}
}
if i run the above code it's come to try block and not move to next line
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);"
some times code move to next line and result come. but most of time it's not go to next line.
how to overcome this. why this problem occur?
you need to add a timeout procedure by your self.
Geolocator geolocator = new Geolocator();
// get the async task
var asyncResult = geolocator.GetGeopositionAsync();
var task = asyncResult.AsTask();
// add a race condition - task vs timeout task
var readyTask = await Task.WhenAny(task, Task.Delay(10000));
if (readyTask != task) // timeout wins
throw new TimeoutException();
// position found within timeout
var pos = await task;
return pos;
Refered from GEOLOCATOR.GETGEOPOSITIONASYNC WITH CORRECT TIMEOUT
You missed a word "GeoCoordinate" at the beginning of current line
GeoCoordinate MyCoordinate = new GeoCoordinate
After you get your current position (GeoCoordinate), do this:
private void findAddress(GeoCoordinate myCoordinate)
{
if (reverseGeocode != null) reverseGeocode = null;
reverseGeocode = new ReverseGeocodeQuery();
reverseGeocode.GeoCoordinate = myCoordinate;
reverseGeocode.QueryCompleted += reverseGeocode_QueryCompleted;
reverseGeocode.QueryAsync();
}
void reverseGeocode_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
if (e.Error == null && e.Result.Count > 0)
{
//Here you got all information about your current coordinate/position
MapAddress myPositionAddress = null;
myPositionAddress = e.Result.FirstOrDefault().Information.Address;
}
}
Related
With the await of MapLocationFinder my program still runs, even after trying to close it with Application.Current.Shutdown();. I'm a beginer.
I already tried to use CancellationToken or run this as Task. But I don't know if I had done this in the right way. I tried different thinks for some hours but nothing worked for me.
private async Task GetLocation()
{
var accesStatus = await Geolocator.RequestAccessAsync();
switch (accesStatus)
{
case GeolocationAccessStatus.Allowed:
// locate user
var locator = new Windows.Devices.Geolocation.Geolocator();
var location = await locator.GetGeopositionAsync();
var position = location.Coordinate.Point.Position;
// get city name
Geopoint geopoint = new Geopoint(new BasicGeoposition
{
Latitude = position.Latitude,
Longitude = position.Longitude
});
Here the problem starts
MapLocationFinderResult result = await MapLocationFinder.FindLocationsAtAsync(geopoint, MapLocationDesiredAccuracy.Low);
if (result.Status == MapLocationFinderStatus.Success)
{
locationBlock.Text = "City: " + result.Locations[0].Address.Town;
}
problem ended, the rest is just for the context
// calculate time
int[] sun = SunDate.CalculateSunriseSunset(51.434406, 6.762329);
var sunrise = new DateTime(1, 1, 1, sun[0] / 60, sun[0] - (sun[0] / 60) * 60, 0);
var sunset = new DateTime(1, 1, 1, sun[1] / 60, sun[1] - (sun[1] / 60) * 60, 0);
//fit UI
lightStartBox.Text = sunrise.Hour.ToString();
darkStartBox.Text = sunset.Hour.ToString();
// apply settings
lightStartBox.IsEnabled = false;
darkStartBox.IsEnabled = false;
break;
case GeolocationAccessStatus.Denied:
locationCheckBox.IsChecked = false;
locationBlock.Text = "The App needs permission to location";
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));
break;
case GeolocationAccessStatus.Unspecified:
locationCheckBox.IsChecked = false;
locationBlock.Text = "The App needs permission to location";
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));
break;
}
return;
}
If I close the program, it should also end the await task. Better: It should end the operation after he got the info.
If I close the program, it should also end the await task. Better: It should end the operation after he got the info.
I have run your code, but I could not reproduce the issue, I could get MapLocationFinderResult with low delay. I found you used MapLocationDesiredAccuracy.Low parameter. And it will leverage the maps disk cache to get accurate info up to the city level. maps disk cache may cause this issue. You could try to use MapLocationDesiredAccuracy.High parameter.
As you see, FindLocationsAtAsync is IAsyncOperation method. So, you could cancel it manually or set timeout cancel token.
For example
private IAsyncOperation<string> GetAsyncOperation()
{
return AsyncInfo.Run<string>(
(token) => // CancellationToken token
Task.Run<string>(
() =>
{
token.WaitHandle.WaitOne(3000);
token.ThrowIfCancellationRequested();
return "hello";
},
token));
}
private IAsyncOperation<string> operation;
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
operation = GetAsyncOperation();
var res = await operation;
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("method end");
}
}
private void Cancel_Button_Click(object sender, RoutedEventArgs e)
{
operation?.Cancel();
}
Set Timeout
private async void Button_Click(object sender, RoutedEventArgs e)
{
var source = new CancellationTokenSource(4000);
var res = await GetAsyncOperation().AsTask(source.Token);
}
Looks like this is a known bug
To work-around it I ended up setting a static flag on my App class so that when the app was shutting down it would force kill the process.
// Before call to MapLocationFinder.FindLocationsAsync()
App.RequiresProcessKill = true;
and then in my shutdown process (ie in the OnClosed method of your main window) I forced closed the app if neccessary:
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
if (App.RequiresProcessKill)
{
var self = Process.GetCurrentProcess();
self.Kill();
}
}
The WPF code below hangs forever when network connection is lost for 3 or more minutes. When connection is restored it neither throws nor continues downloading nor timeouts. If network connection is lost for a shorter period say half a minute, it throws after connection is restored. How can i make it more robust to survive network outage?
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
NetworkChange.NetworkAvailabilityChanged +=
(sender, e) => Dispatcher.Invoke(delegate()
{
this.Title = "Network is " + (e.IsAvailable ? " available" : "down");
});
}
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
try {
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
btnDownload.Content = "Downloaded";
}
}
catch (Exception ex)
{
btnDownload.Content = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
btnDownload.IsEnabled = true;
}
}
}
UPDATE
Current solution is based on restarting Timer in DownloadProgressChangedEventHandler, so the timer fires only if no DownloadProgressChanged events occur within the timeout. Looks like an ugly hack, still looking for a better solution.
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
// Time needed to restore network connection
const int TIMEOUT = 30 * 1000;
public MainWindow()
{
InitializeComponent();
}
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Timer timer = new Timer((o) =>
{
// Force async cancellation
cts.Cancel();
}
, null //state
, TIMEOUT
, Timeout.Infinite // once
);
DownloadProgressChangedEventHandler handler = (sa, ea) =>
{
// Restart timer
if (ea.BytesReceived < ea.TotalBytesToReceive && timer != null)
{
timer.Change(TIMEOUT, Timeout.Infinite);
}
};
btnDownload.Content = await DownloadFileTA(token, handler);
// Note ProgressCallback will fire once again after awaited.
timer.Dispose();
btnDownload.IsEnabled = true;
}
private async Task<string> DownloadFileTA(CancellationToken token, DownloadProgressChangedEventHandler handler)
{
string res = null;
WebClient wcl = new WebClient();
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
wcl.DownloadProgressChanged += handler;
try
{
using (token.Register(() => wcl.CancelAsync()))
{
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
}
res = "Downloaded";
}
catch (Exception ex)
{
res = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
wcl.Dispose();
return res;
}
}
}
You need to implement proper timeout for that download. But you don't need to use timer, just use Task.Delay and Task.WaitAny. For example:
static async Task DownloadFile(string url, string output, TimeSpan timeout) {
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
var download = wcl.DownloadFileTaskAsync(url, output);
// await two tasks - download and delay, whichever completes first
await Task.WhenAny(Task.Delay(timeout), download);
var exception = download.Exception; // need to observe exception, if any
bool cancelled = !download.IsCompleted && exception == null;
// download is not completed yet, nor it is failed - cancel
if (cancelled) {
wcl.CancelAsync();
}
if (cancelled || exception != null) {
// delete partially downloaded file if any (note - need to do with retry, might not work with a first try, because CancelAsync is not immediate)
int fails = 0;
while (true) {
try {
File.Delete(output);
break;
}
catch {
fails++;
if (fails >= 10)
break;
await Task.Delay(1000);
}
}
}
if (exception != null) {
throw new Exception("Failed to download file", exception);
}
if (cancelled) {
throw new Exception($"Failed to download file (timeout reached: {timeout})");
}
}
}
Usage:
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
// Time needed to restore network connection
TimeSpam TIMEOUT = TimeSpan.FromSeconds(30);
DownloadFile(SRC,TARGET, TIMEOUT); // might want to await this to handle exceptions
Update in response to comment. If you want timeout based on received data, not on whole operation time, it's also possible with Task.Delay. For example:
static async Task DownloadFile(string url, string output, TimeSpan timeout)
{
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
DateTime? lastReceived = null;
wcl.DownloadProgressChanged += (o, e) =>
{
lastReceived = DateTime.Now;
};
var download = wcl.DownloadFileTaskAsync(url, output);
// await two tasks - download and delay, whichever completes first
// do that until download fails, completes, or timeout expires
while (lastReceived == null || DateTime.Now - lastReceived < timeout) {
await Task.WhenAny(Task.Delay(1000), download); // you can replace 1 second with more reasonable value
if (download.IsCompleted || download.IsCanceled || download.Exception != null)
break;
}
var exception = download.Exception; // need to observe exception, if any
bool cancelled = !download.IsCompleted && exception == null;
// download is not completed yet, nor it is failed - cancel
if (cancelled)
{
wcl.CancelAsync();
}
if (cancelled || exception != null)
{
// delete partially downloaded file if any (note - need to do with retry, might not work with a first try, because CancelAsync is not immediate)
int fails = 0;
while (true)
{
try
{
File.Delete(output);
break;
}
catch
{
fails++;
if (fails >= 10)
break;
await Task.Delay(1000);
}
}
}
if (exception != null)
{
throw new Exception("Failed to download file", exception);
}
if (cancelled)
{
throw new Exception($"Failed to download file (timeout reached: {timeout})");
}
}
}
Personally, if I were to make a robust download solution, I would add a Network connection monitor because that's what we are actually waiting for. For simplicity, something like this will be enough.
online = true;
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
_isNetworkOnline = NetworkInterface.GetIsNetworkAvailable();
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
online = e.IsAvailable;
}
Then you can actually check for network availability and wait as appropriate before you attempt to download or progress... I will definitely accept that a simple ping solution seems to work better than this at times based on experience.
Depending on the size of what you're downloading, monitoring the network speed may also help so you can decide how to chunk in case of choppy connections. Take a look at this project for ideas.
I try activate a progressbar, while the app is searching for the location (after pressing a button)
how can i solve it the best way?
the best would somehow to get an if else in there, wheater i got (the rigth) data from the geolocator and check that.
private async void Ellipse_Tap (object sender, System.Windows.Input.GestureEventArgs e)
{
Geolocator geolocator = new Geolocator();
//Set his accuracy in Meters
geolocator.DesiredAccuracyInMeters = 50;
try
{
//The await guarantee the calls to be returned on the thread from which they were called
//Since it is call directly from the UI thread, the code is able to access and modify the UI directly when the call returns.
Geoposition geoposition = await geolocator.GetGeopositionAsync(
maximumAge: TimeSpan.FromMinutes(5),
timeout: TimeSpan.FromSeconds(10)
);
//Relativer Nullpunkt
delta_y = geoposition.Coordinate.Latitude - y;
delta_x = geoposition.Coordinate.Longitude - x;
Path.Visibility = Visibility.Visible;
}
//If an error is catch 2 are the main causes: the first is that you forgot to includ ID_CAP_LOCATION in your app manifest.
//The second is that the user doesn't turned on the Location Services
catch (Exception ex)
{
if ((uint)ex.HResult == 0x80004004)
{
MessageBox.Show("Location is disabled in phone settings.");
return;
//Application.Current.Terminate();
}
//else
{
// something else happened during the acquisition of the location
}
}
}
Assuming you are using the ProgressIndicator in the SystemTry, Add the following to the OnNavigatedTo Method
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
SystemTray.ProgressIndicator = new ProgressIndicator();
}
Then create this method to set the ProgressIndicator.
private void DisplayProgressIndicator(bool isvisible, string message = "")
{
SystemTray.ProgressIndicator.Text = message;
SystemTray.ProgressIndicator.IsIndeterminate = isvisible;
SystemTray.ProgressIndicator.IsVisible = isvisible;
}
Then use the method created in the Eclips_Tap method.
private async void Ellipse_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracyInMeters = 50;
try
{
DisplayProgressIndicator(true, "Finding current location..."); // < SET THE PROGRESS INDICATOR
Geoposition geoposition = await geolocator.GetGeopositionAsync(
maximumAge: TimeSpan.FromMinutes(5),
timeout: TimeSpan.FromSeconds(10)
);
delta_y = geoposition.Coordinate.Latitude - y;
delta_x = geoposition.Coordinate.Longitude - x;
Path.Visibility = Visibility.Visible;
DisplayProgressIndicator(false); // << UNSET PROGRESS INDICATOR
}
catch (Exception ex)
{
if ((uint)ex.HResult == 0x80004004)
{
MessageBox.Show("Location is disabled in phone settings.");
return;
}
}
}
Hope this helps..
I am launching the Location settings if it is disabled and trying to get the current location using the below code.
if (locator.LocationStatus == PositionStatus.Disabled)
{
MessageBox.Show("Please enable the Location services", "Alert", MessageBoxButton.OK);
await Launcher.LaunchUriAsync(new Uri("ms-settings-location:"));
}
if (locator.LocationStatus == PositionStatus.Ready)
{
Geoposition geoposition;
Geocoordinate geocoordinate;
GeoCoordinate geoCor = null;
geoposition = await locator.GetGeopositionAsync();
geocoordinate = geoposition.Coordinate;
geoCor = CoordinateConverter.ConvertGeocoordinate(geocoordinate);
ReverseGeocodeQuery reverseQuery = new ReverseGeocodeQuery
{
GeoCoordinate = geoCor
};
}
once the "await" is executed, simply its moving to next statement. So not getting the proper result. I know await will work asynchronously but what about the next statements which are based one await result?
geoposition = await geolocator.GetGeopositionAsync();
geocoordinate = geoposition.Coordinate;
geoCor = CoordinateConverter.ConvertGeocoordinate(geocoordinate);
ReverseGeocodeQuery reverseQuery = new ReverseGeocodeQuery
{
GeoCoordinate = geoCor
};
reverseQuery.QueryCompleted += (s, e) =>
{
if (e.Error != null)
return;
if (e.Result != null && e.Result.Count > 0 && e.Result[0].Information != null && e.Result[0].Information.Address != null)
city = e.Result[0].Information.Address.City;
};
reverseQuery.QueryAsync();
this.mapWithMyLocation.Center = geoCor;
this.mapWithMyLocation.ZoomLevel = 10;
its showing geocoordinates correctly...but not getting the address.
If I understood your question right, then you should watch for location changed event or specify desired report interval. For example:
{
...
locator.DesiredAccuracy = PositionAccuracy.High;
locator.MovementThreshold = 5d;
// locator.ReportInterval = (uint)TimeSpan.FromSeconds(5).TotalMilliseconds;
locator.PositionChanged += RaiseLocationChanged;
...
}
private void RaiseLocationChanged(Geolocator sender, PositionChangedEventArgs args)
{
// Your reverse geocode etc. logic might go here...
var location = CoordinateConverter.ConvertGeocoordinate(args.Position.Coordinate);
}
current I use this code to get GPS:
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.Default;
geolocator.DesiredAccuracyInMeters = 50;
try
{
Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30));
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);
}
catch (Exception ex)
{
if (ex.Message.Contains("This operation returned because the timeout period expired."))
{
MessageBox.Show("GPS is taking too long too complete. Pleaes try again.");
this.SetProgressIndicator(false);
RadBusyIndicator.IsRunning = false;
return;
}
else
{
this.SetProgressIndicator(false);
RadBusyIndicator.IsRunning = false;
return;
}
};
But it always takes too long to complete, as you can see I set timeout 30s but not sure why
it doesn't show timeout exception when took more than 30s.
I'm getting stuck on this issue. Does anyone have any idea?
Make sure the wifi or cellphone device is on, this enables the fallback methods to be used when the GPS device can't find a signal.
Someone with more or less the same problem made another thread in here:
GetGeopositionAsync does not return
More information on the GeoLocator class:
http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.geolocation.geolocator#properties
I don't know why too, but TimeSpanis realy slow, but doing it with ReportInterval works fine:
geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.High;
geolocator.ReportInterval = 2000;
geolocator.PositionChanged += geolocator_PositionChanged;
private void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
try
{
Dispatcher.BeginInvoke(() =>
{
myPosition = args.Position.Coordinate.ToGeoCoordinate();
});
}
catch(Exception ex)
{
if (ex.Data == null) throw;
else MessageBox.Show("Exception while Tracking: " + ex.InnerException.ToString());
}
}