[Bug] iOS RELEASE only: f9p Button + CommunityToolkit.AsyncCommand or a Clicked event mysteriously stops firing
Description
The button in question is a Back button that drives the Position property of a CollectionView. It should be always enabled, except when it's a first page of a collection view. (Position ==0) The XAML and code below actually works in all the simulators and also on Android Release build.
However, on iOS Release build the following happens: When you jump between pages like this: 1-2-1-2-1-2 - at some point the Command event handler stops firing. In fact, even Clicked event handler stops firing, as I found by looking at the app's debug telemetry stream. The button stays Enabled, but tapping doesn't produce any events.
NOTE: When the same Page is created and used in another place in the app - it works. A mystery!
WORKAROUND: Replace f2p:Button with a regular Xamarin Button.
Feel free to close, I just want to track a workaround for people's convenience. There's some work to have a regular Button look as fancy as f9p:Button, but at least I don't have to debug my app by a telemetry log stream.
XAML:
<Button x:Name="prevButton" Grid.Column="0" BackgroundColor="{StaticResource GeneralButtonBackground}" TextColor="{StaticResource GeneralButtonText}" CornerRadius="1" Text="Back" FontSize="Medium" Command="{Binding PreviousPageCommand}" CommandParameter="{Binding BackEnabled, Mode=OneWay}" >
Code behind:
public AsyncCommand PreviousPageCommand { get; private set; }
PreviousPageCommand = new AsyncCommand(
() => ExecuteBackCommand(),
param => param is bool canDo && canDo == true,
continueOnCapturedContext: true,
allowsMultipleExecutions: false);
public bool BackEnabled => CanBackPage();
private bool CanBackPage()
{
var ce = true;
var p = _position;
if (p > 0)
ce = IsValid;
else
ce = false;
TelemetryManager.WriteTrace($"Assessment: CanBackPage called for {p}, result={ce}");
return ce;
}
public async Task ExecuteBackCommand()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
if (Volatile.Read(ref _isMovingBetweenPages))
{
TelemetryManager.WriteTrace("Assessment: moving, ExecuteBackCommand=no-op");
return;
}
try
{
TelemetryManager.WriteTrace("Assessment: entered ExecuteBackCommand, setting moving=true");
Volatile.Write(ref _isMovingBetweenPages, true);
if (Position > 0)
{
Position -= 1;
}
}
finally
{
TelemetryManager.WriteTrace("Assessment: exited ExecuteBackCommand, setting moving=false");
Volatile.Write(ref _isMovingBetweenPages, false);
}
}
-
Version with issue: Latest f9p, latest Xamarin
-
Last known good version: Unknown
-
IDE: VS2019
-
Platform Target Frameworks: - iOS: Release build only!
-
Affected Devices: iPhone SE 2021 edition
At some point I let go of the Command entirely and managed the IsEnabled directly & called ExecuteBackCommand() directly from the Clicked event handler. Same result. Eliminating all the other possiblities - it's something in the f9p:Button that glitches after repeated calls to IsEnabled?
Transient bugs are hard, so I am not placing the blame here. But this problem ate a week of my free time and it deserves to be documented :)