issues with async and await in wp8 - c#

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);
}

Related

Why is this display alert not working? it worked fine when i tried it in a button Clicked event, but its not working in a Function

1 ) Its a weather Api and i want it to display no internet connection when there is no internet connected to the device.
public async void method()
{
Indicator.IsRunning = true;
Weather weather = await GetWeather(nameplace.Text);
if (weather != null)
{
if (weather.message == "city not found")
{
txtLocation.Text = "city not found";
}
else
{
Location.Text = weather.Title;
Temperature.Text = weather.Temperature;
Temperature.Text += "°";
txtWind.Text = weather.Wind;
Humidity.Text = weather.Humidity;
Sunrise.Text = weather.Sunrise;
Sunset.Text = weather.Sunset;
double condition = Convert.ToDouble(weather.Condition);
if (condition >= 0 && condition < 30)
{
Condition.Text = "Clear Sky";
}
else if (condition >= 30)
{
Condition.Text = "Cloudy";
}
}
}
else
{
await DisplayAlert("Alert", "Sorry ! No internet connection","Ok")`
}
}
3) // Below in a getservice function i have
if (Plugin.Connectivity.CrossConnectivity.Current.IsConnected)
{
var response = await client.GetAsync(QueryString);
// pQueryString is the http request
_httpStatusCode = response.StatusCode.ToString();
if (response == null)
{
return "Sorry! No record Found.";
}
else if (response != null)
{
string json = response.Content.ReadAsStringAsync().Result;
data = JsonConvert.DeserializeObject(json);
}
}
else
{
data = null;
}
return data;
4) i have return null and put a condition in there so that it can display an alert saying no internet connection
It is possible that your async void method messes with the Thread context, and that you end up not calling your code in the ui thread.
You could try this:
Xamarin.Forms.Device.BeginInvokeOnMainThread(
() => DisplayAlert("Alert", "Sorry ! No internet connection","Ok"));
Also it's a bad design to put UI code in your service layer.
Your should call your DisplayAlert code in your ViewModel not in your service.

Cannot open file immediately after downloading from OneDrive

after downloading a JPG file from OneDrive successfully under Windows 8.1, I am not able to open it and use the stream as image source immediately. Instead, my app must run in a waiting loop to retry the opening until the exception "Error HRESULT E_FAIL has been returned from a call to a COM component" does not occur anymore. Or the app must inform the user to retry the action. After about one second or so, the file can be opened and the stream can be used as image source. This problem occurs if the JPG file was initially not available offline and my app downloads it. I want to know if anybody has a better solution for that problem. Here is some of my code:
private async void LoadFileButton_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.ViewMode = PickerViewMode.Thumbnail;
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".jpe");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".gif");
Stream stream = null;
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
var basicProperties = await file.GetBasicPropertiesAsync();
var props = await basicProperties.RetrievePropertiesAsync(
new string[] { "System.OfflineAvailability", "System.StorageProviderFileRemoteUri" });
if (props.ContainsKey("System.OfflineAvailability"))
{
var offline = (uint)props["System.OfflineAvailability"];
if (offline == 0)
{
if (file.Provider.DisplayName == "OneDrive")
{
if (props.ContainsKey("System.StorageProviderFileRemoteUri"))
{
var uri = (string)props["System.StorageProviderFileRemoteUri"];
var res = await GameStorage.DownloadOneDriveFile(file, uri, _downloadProgressBar);
if (res is string)
{
await App.InformUserAsync(res.ToString(), _title.Text);
return;
}
stream = (Stream)res;
}
}
else
{
await App.InformUserAsync(String.Format(
App.GetString("MakeFileOfflinePrompt", "GameManagement"),
file.Path), _title.Text);
return;
}
}
}
if (stream == null)
{
stream = await file.OpenStreamForReadAsync();
}
await _photoClipper.SetDisplayImageStreamAsync(stream);
_clipPhotoButton.IsEnabled = true;
}
}
internal static async Task<object> DownloadOneDriveFile(StorageFile file, string url,
ProgressBar progressBar = null)
{
if (progressBar != null)
{
progressBar.Visibility = Visibility.Visible;
progressBar.Value = 1;
}
if (__liveClient == null)
{
var msg = await ConnectLive();
if (!String.IsNullOrEmpty(msg))
{
return msg;
}
}
var uri = new Uri(WebUtility.UrlDecode(url));
var pathElements = uri.LocalPath.Split(new char[] { '/' },
StringSplitOptions.RemoveEmptyEntries);
var parentId = "folder." + pathElements[0];
IDictionary<string, object> props = null;
for (var i = 1; i < pathElements.Length; i++)
{
props = await FindOneDrivePathElement(parentId, pathElements[i]);
if (props == null)
{
return String.Format(App.GetString("OneDrivePathElementNotFound",
"GameManagement"), pathElements[i], uri);
}
parentId = props["id"].ToString();
if (progressBar != null) progressBar.Value += 1;
}
try
{
var operation = await __liveClient.CreateBackgroundDownloadAsync(parentId +
"/content", file);
LiveDownloadOperationResult result = null;
if (progressBar != null)
{
progressBar.Value = 10;
var progressHandler = new Progress<LiveOperationProgress>(
(progress) => { progressBar.Value = progress.ProgressPercentage; });
var cts = new CancellationTokenSource();
result = await operation.StartAsync(cts.Token, progressHandler);
}
else
{
result = await operation.StartAsync();
}
var trialsCount = 0;
string openErr = null;
Stream stream = null;
while (trialsCount < 5)
{
try
{
stream = await result.File.OpenStreamForReadAsync();
break;
}
catch (Exception ex)
{
openErr = ex.Message;
}
trialsCount += 1;
await App.SuspendAsync(1000);
}
if (stream != null)
{
return stream;
}
return String.Format(App.GetString("OneDriveCannotOpenDownloadedFile",
"GameManagement"), file.Path, openErr);
}
catch (Exception ex)
{
return String.Format(App.GetString("OneDriveCannotDownloadFile",
"GameManagement"), file.Path, ex.Message);
}
finally
{
if (progressBar != null)
{
progressBar.Visibility = Visibility.Collapsed;
}
}
}
private static async Task<IDictionary<string, object>> FindOneDrivePathElement(
string parentId, string childName)
{
var res = await __liveClient.GetAsync(parentId + "/files");
if (res.Result.ContainsKey("data"))
{
var items = (IList<object>)res.Result["data"];
foreach (var item in items)
{
var props = (IDictionary<string, object>)item;
if (props.ContainsKey("name"))
{
var name = props["name"].ToString();
if (name == childName)
{
if (props.ContainsKey("id"))
{
return props;
}
}
}
}
}
return null;
}
I have tried again to open a "available online-only" file and as by a miracle the exception "Error HRESULT E_FAIL" did not occur any more. For what ever reason, I don't know. But, I really do not need to handle that scenario by myself. Thanks.

windows phone progress bar while searching location

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..

Error in get location windows phone 8

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;
}
}

Nested Asynchronous function in Silverlight

I am trying to call a nested Asynchronous function but I am not getting the required data.
Since I am using a wcf service with Silverlight I can only use Asynchronous functions.
In my code I am saving a set of rows containing userdata. Before I save it I need to check the username is unique. Now I only need to find out the first one and then break out of loop and show a message to the user.for simplicity sake, I have stripped the function of all the extra data and this is how it looks
private void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.CheckIsUserNameUnique += (s, e) =>
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
_UpdatedUsers = new ObservableCollection<User>();
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
};
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}
In this case I am trying to find if the username is unique,show user a message and return.
Obviously it's not as simple as that.I have tried a couple more different ways but it didn't work. How do I get this working?
I think you can make your life easier by adding a couple of helper functions. The first one is an asynchronous function that checks whether a user is unique. You may need to add some code to set tcs.SetException if there is an error.
private Task<bool> IsUserUniqueAsync(UserViewModel user, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
dataService.CheckIsUserNameUnique += (s, e) =>
{
tcs.SetResult(e.IsUnique);
};
dataService.IsUserNameUnique(user.UserName, user.UserID, Database.CurrentClient.ClientID);
return tcs.Task;
}
The second one updates all the users asynchrnously
public Task<bool> UpdateUsersAsync(ObservableCollection<User> updatedUsers, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
BusyIndicator = true;
BusyMessage = "Saving...";
dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
tcs.SetResult(e.Success);
};
dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, updatedUsers, _DeletedProjectUsers);
return tcs.Task;
}
Then your SaveUsers method becomes a bit simpler.
private async void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
Dictionary<Task<bool>, User> tasks = new Dictionary<Task<bool>, User>();
// start all tasks in parallel
foreach (UserViewModel _User in _AllUsers)
{
if (_User.Dirty && !_User.IsBlank)
{
tasks.Add(IsUserUniqueAsync(_User, _dataService), _User);
}
}
// process each task as it completes
while(tasks.Count() > 0 )
{
var task = await Task.WhenAny(tasks.Keys.ToArray());
if(task.Result)
{
_UpdatedUsers.Add(_User.SaveAsUser());
}
else
{
MessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
tasks.Remove(task);
}
if( await UpdateUsersAsync(_UpdatedUsers, _dataService))
{
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
}
Your code would more or less look like this.
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
int _verifiedUsersCount = 0;
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
//Verify unique users
private void SaveUsers(bool CloseForm)
{
_dataService.CheckIsUserNameUnique += CheckIsUserNameUnique;
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
}
}
//Store verified users to save
private void CheckIsUserNameUnique(object s, CheckIsUserNameUniqueEventArgs e)
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
}
verifiedUsersCount++;
//Call after all the users have been verified for uniqueness
if (_AllUsers.Count() == verifiedUsersCount)
{
OnUniqueUserVerifyComplete();
}
}
//Save verified users
private void OnUniqueUserVerifyComplete()
{
//No unique users
if (_UpdatedUsers.Count < 1) { return; }
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
};
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}

Categories