Blazor Time Localisation - time

Hi i am in trouble with time, I want to display the time and update it in realtime
I already installed "Install-Package Blazored.Localisation"
below is the sample code
string currentLocalTime = "";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender) // Remove the firstRender check if you want the current local time displayed to continuously update.
{ // Leave the above firstRender check in place to ensure that the call to StateHasChanged() does not trigger an endless update loop.
var browserDateTime = await browserDateTimeProvider.GetInstance();
currentLocalTime = browserDateTime.Now.ToString();
StateHasChanged();
}
}

I realize that you can remove first render check if you want to continuously update.
Just remove If statement.
string currentLocalTime = "";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
var browserDateTime = await browserDateTimeProvider.GetInstance();
currentLocalTime = browserDateTime.Now.ToString();
StateHasChanged();
}

Related

What would cause a for / foreach loop to break without explicitly calling a break?

I have a durable function that calls a method that simply adds a row to an efcore object. It doesn't call db save.
When I step through the code, and get to the for loop, it will immediately jump to the line after the for loop. If I step into the call to add the efcore object, and back to the for loop, it continues and loops to the next item. If I press F5 to let it go without debugging, it immediately "breaks" the for loop.
It jumps out of the for loop where i wrote //HERE!!!!!!
I'm pulling my hair out on this one.
obligatory code:
//foreach (stagingFileMap stagingFileMap in fileMaps)
foreach (stagingFileMap stagingFileMap in fileMaps)
{
if (ActivitySyncHelper.IsSyncCancelled(aso, _configuration))
{
break;
}
if (!string.IsNullOrEmpty(stagingFileMap.URL))
{
// Ensure the url is valid
try
{
string x = await GetTotalBytes(stagingFileMap.URL);
double.TryParse(x, out double fileByteCount);
if (fileByteCount > 0)
{
// Create or update the video in vimeo
if (string.IsNullOrEmpty(stagingFileMap.VimeoId))
{
// Azure won't be ready with its backups, so use confex host for video 'get'
string title = stagingFileMap.FileName;
if (stagingFileMap.FileName.Length > 127)
{
title = stagingFileMap.FileName.Substring(0, 127);
}
Video video = vimeoClient.UploadPullLinkAsync(stagingFileMap.URL, title, stagingFileMap.id, meetingIdFolder.Uri).Result;
stagingFileMap.VimeoId = video.Id.ToString();
stagingFileMap.VimeoId = video.Id.ToString();
//HERE!!!!!!
await syncLog.WriteInfoMsg($"Vimeo create {stagingFileMap.FileName}");
//HERE!!!!!!
}
else
{
// Attempt to pull the existing video and update it
if (long.TryParse(stagingFileMap.VimeoId, out long videoId))
{
Video video = vimeoClient.GetVideoAsync(videoId).Result;
if (video.Id.HasValue)
{
Video res = await vimeoClient.UploadPullReplaceAsync(stagingFileMap.URL, video.Id.Value, fileByteCount);
await syncLog.WriteInfoMsg($"Vimeo replace {stagingFileMap.FileName} id {res.Id}");
}
}
}
break;
}
}
catch (Exception ex)
{
// IDK what to do besides skip it and continue
// log something once logging works
await syncLog.WriteErrorMsg(aso, ex.Message);
await syncLog.Save();
continue;
}
// We need to save here requently because if there is big error, all the work syncing to vimeo will be desync with the DB
dbContext.Update(stagingFileMap);
await dbContext.SaveChangesAsync();
await syncLog.Save();
}
}
await dbContext.DisposeAsync();
public async Task WriteInfoMsg( string msg)
{
SyncAttemptDetail sad = new()
{
SyncAttemptId = _id,
Message = msg,
MsgLevel = SyncAttemptMessageLevel.Info,
AddDate = DateTime.UtcNow,
AddUser = "SYSTEM"
};
await _dbContext.SyncAttemptDetail.AddAsync(sad);
}
I'm dumb. Theres LITERALLY a break command in there.
The await will create a task and immediately return it (the debugger will follow this path too). The loop will continue in the task.
To attach the debugger to the task, add a break point after the await.

How to properly implement location changes listener to xamarin forms?

I have a listener that captures the location every 10 seconds or 100 meters or so. I am using
xam.plugin.geolocator
to implement the listener. My problem is the location listener is not working(meaning the changes in location were not capturing or saved in the location cache) when my application is minimized or the application is opened but the phone is locked.
Here is my code:
async Task StartListening()
{
if (!CrossGeolocator.Current.IsListening)
{
var defaultgpsaccuracy = Convert.ToDouble(Preferences.Get("gpsaccuracy", String.Empty, "private_prefs"));
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(10), defaultgpsaccuracy, false, new Plugin.Geolocator.Abstractions.ListenerSettings
{
ActivityType = Plugin.Geolocator.Abstractions.ActivityType.Other,
AllowBackgroundUpdates = true,
DeferLocationUpdates = true,
DeferralDistanceMeters = 1,
DeferralTime = TimeSpan.FromSeconds(1),
ListenForSignificantChanges = true,
PauseLocationUpdatesAutomatically = false
});
}
}
I place this code in the first view/page of my application in my login.xaml.cs
Here are my questions:
How can I implement the listener properly so that when the application minimized or the phone/device is locked it still captures the changes of location?
What is the best GPS settings I need to capture the changes in location faster and accurately? Right now, my current settings are capturing the location every 10 seconds or 100 meters.
First you need to init StartListening then create event handlers for position changes and error handling
public Position CurrentPosition { get; set; }
public event EventHandler PositionChanged;
Don't forget to init it in your constructor :
CurrentPosition = new Position();
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(20), 10, true);
CrossGeolocator.Current.PositionChanged += PositionChanging;
CrossGeolocator.Current.PositionError += PositionError;
Functions :
`private void PositionChanging(object sender, PositionEventArgs e)
{
CurrentPosition = e.Position;
if (PositionChanged != null)
{
PositionChanged(this, null);
}
}
private void PositionError(object sender, PositionErrorEventArgs e)
{
Debug.WriteLine(e.Error);
}`
You can now call PositionChanged when ever you want the latest position
Don't forget to stop listening :
`public async Task StopListeningAsync()
{
if (!CrossGeolocator.Current.IsListening)
return;
await CrossGeolocator.Current.StopListeningAsync();
CrossGeolocator.Current.PositionChanged -= PositionChanging;
CrossGeolocator.Current.PositionError -= PositionError;
}`

Proper way to wait all tasks while still updating the UI thread

I'm trying to download the page source from multiple urls using tasks to download multiple sites at one time. The issue is that I want to keep the UI updated as each individual task completes. When I try to wait all tasks it stops updating the UI until they all finish. Here is the current code that I am using.
EDIT: I'm assuming I was down voted due to me not explaining well enough. I guess a better way to put this is why is the continueWith not being run before Task.WaitAll. I want the UI to update on each completion of the source being downloaded. Once that is all finished then the listbox would be updated to let the user know everything is done.
private void btnGetPages_Click(object sender, EventArgs e)
{
for (int i = 1; i < 11; i++)
{
string url = $"http://someURL/page-{i}.html";
listBoxStatus.Items.Add($"Downloading source from {url}...");
Task t = new Task(() =>
{
DownloadSource(url);
});
t.ContinueWith(prevTask => listBoxStatus.Items.Add($"Finished Downloading {url} source..."), TaskScheduler.FromCurrentSynchronizationContext());
tasks.Add(t);
t.Start();
}
Task.WaitAll(tasks.ToArray());
listBoxStatus.Items.Add("All Source files have completed...");
}
private void DownloadSource(string url)
{
var web = new HtmlWeb();
var doc = web.Load(url);
pageSource += doc.Text;
}
You really should use an asynchronous download method based on HttpClient instead of the synchronous method you are showing. Lacking that, I'll use this one:
private async Task DownloadSourceAsync(string url)
{
await Task.Run(() => DownloadSource(url));
listBoxStatus.Items.Add($"Finished Downloading {url} source...");
}
Then, you can make your btnGetPages_Click method something like this:
private async void btnGetPages_Click(object sender, EventArgs e)
{
var tasks = new List<Task>();
for (int i = 1; i < 11; i++)
{
string url = $"http://someURL/page-{i}.html";
listBoxStatus.Items.Add($"Downloading source from {url}...");
tasks.Add(DownloadSourceAsync(url));
}
Task.WaitAll(tasks.ToArray());
listBoxStatus.Items.Add("All Source files have completed...");
}

Xamarin iOS RefreshControl is stuck

I have a problem with RefreshControl... I have this code:
In ViewDidLoad() I call method InitializeRefreshControl();
private void InitializeRefreshControl()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0))
{
//UIRefreshControl iOS6
ordersCollectionView.RefreshControl = new UIRefreshControl();
ordersCollectionView.RefreshControl.AttributedTitle = new NSAttributedString("Pull To Refresh",
new UIStringAttributes()
{
ForegroundColor = UIColor.Red,
KerningAdjustment = 3
});
ordersCollectionView.RefreshControl.ValueChanged += HandleValueChanged;
}
else
{
// old style refresh button and no PassKit for older iOS
NavigationItem.SetRightBarButtonItem(new UIBarButtonItem(UIBarButtonSystemItem.Refresh), false);
NavigationItem.RightBarButtonItem.Clicked += (sender, e) => { Refresh(); };
}
}
HandleValueChange method and Refresh merhod is here:
private void HandleValueChanged(object sender, EventArgs e)
{
ordersCollectionView.RefreshControl.BeginRefreshing();
ordersCollectionView.RefreshControl.AttributedTitle = new NSAttributedString("Refreshing",
new UIStringAttributes()
{
ForegroundColor = UIColor.Blue,
KerningAdjustment = 5
});
Refresh();
ordersCollectionView.RefreshControl.EndRefreshing();
}
private void Refresh()
{
var viewModel = (OrdersViewModel)DataContext;
viewModel.OnReloadData();
}
My problem is when I pull down collectionVIew so Refresh loading is displayed but is stuck no loading effect and still with text "Pull to refresh". When method Refresh end so for 0,1ms is showing loading effect and text "Refreshing" but not before method Refresh... Someone know how solve this problem? Thanks for answer.
It looks like the issue is related to the Refresh(); method being synchronous. You'll need to make this operation happen in the background so that the UI thread is free to provide the animation for the RefreshControl. For example:
private async void HandleValueChanged(object sender, EventArgs e)
{
ordersCollectionView.RefreshControl.BeginRefreshing();
ordersCollectionView.RefreshControl.AttributedTitle = new NSAttributedString("Refreshing",
new UIStringAttributes()
{
ForegroundColor = UIColor.Blue,
KerningAdjustment = 5
});
// await a Task so that operation is done in the background
await Refresh();
ordersCollectionView.RefreshControl.EndRefreshing();
}
// Marked async and Task returning
private async Task Refresh()
{
var viewModel = (OrdersViewModel)DataContext;
// Need to update this method to be a Task returning, async method.
await viewModel.OnReloadData();
}
The above code refactors what you had to use async/await and Tasks. You may need to refactor some more of your code to make that work, including the OnReloadData() method.
There are lots of resources for getting started with Tasks, async and await. I can start you off with this reference from the Xamarin blog.

Windows 8.1 store apps OnCommandsRequested doesn't add ApplicationCommands when async used

On the App.xaml.cs I have the following code
private async void OnCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs e)
{
var loader = ResourceLoader.GetForCurrentView();
var generalCommand = new SettingsCommand("General Settings", "General Settings", handler =>
{
var generalSettings = new GeneralSettingsFlyout();
generalSettings.Show();
});
e.Request.ApplicationCommands.Add(generalCommand);
object data;
IAuthService _authService = new AuthService();
if (Global.UserId == 0)
data = await _authService.GetSettingValueBySettingName(DatabaseType.GeneralDb, ApplicationConstants.GeneralDbSettingNames.ShowSupportInfo);
else
data = await _authService.GetSettingValueBySettingName(DatabaseType.UserDb, ApplicationConstants.UserDbSettingNames.ShowSupportInfo);
if (data != null && data.ToString().Equals("1"))
{
var supportCommand = new SettingsCommand("Support", "Support", handler =>
{
var supportPane = new SupportFlyout();
supportPane.Show();
});
e.Request.ApplicationCommands.Add(supportCommand);
}
var aboutCommand = new SettingsCommand("About", loader.GetString("Settings_OptionLabels_About"), handler =>
{
var aboutPane = new About();
aboutPane.Show();
});
e.Request.ApplicationCommands.Add(aboutCommand);
}
This code adds the setting "General Settings" but neither "Support" or "About" commands. Can anyone advice what's wrong with this code?
Instead of querying the commands from your service when they are requested you'll need to query them ahead of time and then add the already known commands.
You cannot use await in OnCommandsRequested.
A method returns when it gets to the first await, so only commands added to the request before the await will be used.
Since the SettingsPaneCommandsRequestedEventArgs doesn't provide a deferral there is no way to tell the requester to wait for internal async calls to complete.
Note also that SettingsPane is deprecated and not recommended for new app development for Windows 10.

Resources