baskren / Forms9Patch

Simplify image management and text formatting in your Xamarin.Forms apps
http://Forms9Patch.com
Other
128 stars 33 forks source link

[Bug] iOS RELEASE only: f9p Button + CommunityToolkit.AsyncCommand or a Clicked event mysteriously stops firing #112

Open smalgin opened 1 year ago

smalgin commented 1 year ago

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);
            }
        }
smalgin commented 1 year ago

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 :)