Skip to content

[Android/iOS] Fix SwipeItem visibility change causing double command execution in Execute mode#35087

Merged
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-7580
Apr 25, 2026
Merged

[Android/iOS] Fix SwipeItem visibility change causing double command execution in Execute mode#35087
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-7580

Conversation

@praveenkumarkarunanithi
Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue.
Thank you!

Root Cause

In SwipeView Execute mode, when a swipe crosses the threshold, the framework iterates through all SwipeItems and executes the command for each visible item. The visibility check is performed dynamically during iteration. If the first item’s command changes the visibility of a sibling item (for example, toggling a boolean that controls which SwipeItem is shown), the newly visible item is also picked up and executed within the same loop. This leads to a double invocation, effectively cancelling the user’s intended action.

Description of Change

Updated the Execute mode logic in ValidateSwipeThreshold() to execute only the first visible SwipeItem using FirstOrDefault(GetIsVisible), instead of iterating through all items.

This change aligns Android and iOS with WinUI, where only one SwipeItem is allowed in Execute mode at the platform level. It also removes timing-related issues caused by UI updates during iteration and prevents potential multiple executions when additional SwipeItems are introduced in the future.

Issues Fixed

Fixes #7580

Tested the behaviour in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Screenshots - Android

Before Issue Fix After Issue Fix
BeforeFix.mov
AfterFix.mov

Screenshots - iOS

Before Issue Fix After Issue Fix
BeforeFix.mov
AfterFix.mov

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35087

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35087"

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Apr 22, 2026
@praveenkumarkarunanithi praveenkumarkarunanithi added platform/android platform/ios area-controls-swipeview SwipeView and removed partner/syncfusion Issues / PR's with Syncfusion collaboration labels Apr 22, 2026
@vishnumenon2684 vishnumenon2684 added partner/syncfusion Issues / PR's with Syncfusion collaboration community ✨ Community Contribution labels Apr 22, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review April 22, 2026 13:15
Copilot AI review requested due to automatic review settings April 22, 2026 13:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a SwipeView Execute-mode behavior on Android and iOS where changing a sibling SwipeItem’s visibility during command execution can cause multiple commands to run from a single swipe (Issue #7580).

Changes:

  • Android/iOS: Execute only the first visible SwipeItem in Execute mode instead of iterating and executing all visible items.
  • Adds a HostApp reproduction page (Issue7580) that toggles SwipeItem.IsVisible from the invoked command.
  • Adds an Appium/NUnit UI test to validate the command is invoked exactly once per swipe.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/Core/src/Platform/iOS/MauiSwipeView.cs Changes Execute-mode invocation to execute only the first visible item (prevents double execution).
src/Core/src/Platform/Android/MauiSwipeView.cs Same Execute-mode fix as iOS to align behavior and avoid side effects during enumeration.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue7580.cs Adds UI test that swipes and asserts only one invocation / single state toggle.
src/Controls/tests/TestCases.HostApp/Issues/Issue7580.cs Adds HostApp issue page reproducing visibility-toggled double execution scenario.

Comment on lines +27 to +28
var startX = rect.X + 20;
var endX = startX + 600;
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The drag gesture uses endX = startX + 600, which can exceed the viewport width on smaller devices/simulators (and DragCoordinates performs absolute viewport pointer moves). This can cause out-of-bounds pointer actions and flaky failures. Derive endX from the target element’s bounds (e.g., rect.X + rect.Width - padding) or otherwise clamp the end coordinate to the screen width while still exceeding the swipe threshold.

Suggested change
var startX = rect.X + 20;
var endX = startX + 600;
var padding = 20;
var startX = rect.X + padding;
var endX = global::System.Math.Max(startX + 1, rect.X + rect.Width - padding);

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +71
};
swipeContent.Add(new Label
{
Text = "Swipe right to toggle",
AutomationId = "SwipeTarget",
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwipeTarget AutomationId is attached to the centered label inside the SwipeView content, so GetRect() only covers the label’s small, centered bounds. That makes coordinate-based swipe gestures less reliable (start point is mid-screen and end point calculations can drift out of bounds). Put the AutomationId on the full swipe content container (e.g., the Grid assigned to SwipeView.Content) so the rect represents the intended swipe surface.

Suggested change
};
swipeContent.Add(new Label
{
Text = "Swipe right to toggle",
AutomationId = "SwipeTarget",
AutomationId = "SwipeTarget",
};
swipeContent.Add(new Label
{
Text = "Swipe right to toggle",

Copilot uses AI. Check for mistakes.
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Apr 22, 2026
Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cold you please review the ai's summary?

@dotnet dotnet deleted a comment from MauiBot Apr 24, 2026
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 24, 2026

🤖 AI Summary

👋 @praveenkumarkarunanithi — new AI review results are available. Please review the latest session below.

📊 Review Session37f8680 · fix update · 2026-04-24 22:54 UTC
🚦 Gate — Test Before & After Fix

Test Verification Report

Date: 2026-04-24 22:15:05 | Platform: ANDROID | Status: ✅ PASSED

Summary

Check Expected Actual Result
Tests WITHOUT fix FAIL FAIL
Tests WITH fix PASS PASS

✅ Final Verdict

VERIFICATION PASSED

The tests correctly detect the issue:

  • ✅ Tests FAIL without the fix (as expected - bug is present)
  • ✅ Tests PASS with the fix (as expected - bug is fixed)

Conclusion: The tests properly validate the fix and catch the bug when it's present.


Configuration

Platform: android
Test Filter: Issue7580
Base Branch: main
Merge Base: a38e0bb

Fix Files

  • src/Core/src/Platform/Android/MauiSwipeView.cs
  • src/Core/src/Platform/iOS/MauiSwipeView.cs

Test Results Details

Test Run 1: WITHOUT Fix

Expected: Tests should FAIL (bug is present)
Actual: Tests FAILED ✅

View full test output (without fix)
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 947 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 5.29 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 9.12 sec).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 2.51 sec).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 1.57 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 53 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 34 ms).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 63 ms).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 84 ms).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 63 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 2.85 sec).
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]

Build FAILED.

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:16:52.82
* daemon not running; starting now at tcp:5037
* daemon started successfully
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:09:25.62
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0


Test Run 2: WITH Fix

Expected: Tests should PASS (bug is fixed)
Actual: Tests PASSED ✅

View full test output (with fix)
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  ##vso[build.updatebuildnumber]10.0.60-ci+azdo.13932964
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:07:02.77
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0


Logs

  • Full verification log: /home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35087/PRAgent/gate/verify-tests-fail/verification-log.txt
  • Test output without fix: /home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35087/PRAgent/gate/verify-tests-fail/test-without-fix.log
  • Test output with fix: /home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35087/PRAgent/gate/verify-tests-fail/test-with-fix.log
  • UI test logs: CustomAgentLogsTmp/UITests/

🧪 UI Tests — Category Detection

Detected UI test categories: SwipeView,ViewBaseTests


🔍 Pre-Flight — Context & Validation

Issue: #7580 - Changing visibility on a SwipeItem causes multiple items to be executed
PR: #35087 - [Android/iOS] Fix SwipeItem visibility change causing double command execution in Execute mode
Platforms Affected: Android, iOS (fix); Tizen (not updated — see code review)
Files Changed: 2 implementation, 2 test

Key Findings

  • In SwipeMode.Execute, iterating all visible SwipeItems and executing each creates a race: executing item A can toggle item B from hidden → visible mid-loop, causing item B to also execute unintentionally.
  • Fix replaces foreach loop with FirstOrDefault(GetIsVisible) on both Android and iOS MauiSwipeView.cs, executing only the first visible item.
  • Tizen (src/Core/src/Platform/Tizen/MauiSwipeView.cs) still has the old foreach loop — not updated in this PR.
  • UI test uses hardcoded 600px drag offset which may exceed screen bounds on small devices.
  • A prior Copilot inline review noted: (1) the drag endX = startX + 600 can exceed viewport width; (2) SwipeTarget AutomationId is on a centered Label inside the SwipeView rather than on the full swipe container.

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: medium
Errors: 0 | Warnings: 3 | Suggestions: 3

Key code review findings:

  • ⚠️ src/Core/src/Platform/Tizen/MauiSwipeView.cs — Tizen still uses the old foreach loop, creating a behavioral split (Android/iOS execute first-only; Tizen executes all)
  • ⚠️ Silent behavioral change: any app with multiple visible SwipeItems in Execute mode expecting all to fire will break silently
  • ⚠️ src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue7580.cs:28 — hardcoded endX = startX + 600 may exceed screen width on small devices
  • 💡 Test only verifies one swipe; second swipe assertion would improve coverage
  • 💡 Debug.WriteLine left in HostApp (line 50)
  • 💡 Missing trailing newline in test file

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35087 Replace foreach loop with FirstOrDefault(GetIsVisible) on Android & iOS ✅ PASSED (Gate) Android/MauiSwipeView.cs, iOS/MauiSwipeView.cs Original PR; Tizen not updated

🔬 Code Review — Deep Analysis

Code Review — PR #35087

Independent Assessment

What this changes: In Android/MauiSwipeView.cs and iOS/MauiSwipeView.cs, ValidateSwipeThreshold() is changed from iterating all visible SwipeItems and executing each, to calling FirstOrDefault(GetIsVisible) and executing only the first visible item. New UI test (Issue7580) and HostApp test page are also added.

Inferred motivation: The old foreach loop calls ExecuteSwipeItem() on each visible item sequentially. If executing item A causes item B's visibility to toggle from hidden → visible mid-loop, item B is picked up in the same iteration and also executed — leading to unintended double invocations.


Reconciliation with PR Narrative

Author claims: The fix aligns Android/iOS with WinUI behavior (where Execute mode fires only one item). Root cause correctly identified as dynamic visibility evaluation during iteration.

Agreement/disagreement: The root cause analysis is accurate, and the fix is effective for the reported scenario. The WinUI alignment claim is plausible — WinUI's SwipeItems in Execute mode fires only the triggered item, not all visible ones. One notable gap: the PR does not address Tizen, which contains the identical pre-fix loop.


Findings

⚠️ Warning — Tizen platform not updated — creates persistent cross-platform inconsistency

src/Core/src/Platform/Tizen/MauiSwipeView.cs still uses the old foreach (var swipeItem in swipeItems) { if (GetIsVisible(swipeItem)) ExecuteSwipeItem(swipeItem); } loop. After this PR, Android and iOS execute only the first visible item, but Tizen will continue to execute all visible items. This creates a three-way behavioral split: Windows (native, single-item), Android/iOS (fixed, single-item), Tizen (old, all-items).

⚠️ Warning — Silent behavioral change for legitimate multi-item Execute-mode SwipeViews

The fix changes the observable behavior of any app that intentionally places multiple visible SwipeItems in SwipeMode.Execute and expects all of them to fire on a swipe. This is a correct fix for the reported scenario, but it's a breaking behavioral change for apps relying on the old semantics. There's no deprecation notice or docs update.

⚠️ Warning — Test uses hardcoded pixel drag distance that may be fragile on low-density devices

In Issue7580.cs (shared tests), the drag gesture is computed as:

var endX = startX + 600;
App.DragCoordinates(startX, centerY, endX, centerY);

The HostApp sets Threshold = 250, but the 600-pixel absolute offset may exceed the screen width on low-density or small-screen test devices, causing the drag to be clipped.

💡 Suggestion — Test only validates one swipe; consider verifying second swipe

The test verifies InvokeCount: 1 after one swipe but doesn't verify that a second swipe also invokes exactly once. Adding a second swipe assertion would make the test more robust.

💡 Suggestion — Debug.WriteLine left in HostApp test page

Issue7580.cs (HostApp) line 50 emits debug log on every swipe. Remove or guard with #if DEBUG.

💡 Suggestion — Missing newline at end of test file

TestCases.Shared.Tests/Tests/Issues/Issue7580.cs ends without a trailing newline. dotnet format will flag this.


Devil's Advocate

  • Tizen: Tizen is a lower-priority platform in MAUI and is often left out of platform-specific fixes. However, the code is a direct copy of the iOS/Android pattern, so the fix is trivial. Worth flagging even if intentionally deferred.
  • Behavioral change: The WinUI native SwipeView does not support multiple Execute-mode items at the platform level. The "breaking" scenario is niche, and the fix is arguably more correct than the previous behavior.
  • Hardcoded offset: Many other UI tests in the repo use fixed pixel coordinates. The concern is real but may not manifest given current test device specs.

Verdict: NEEDS_CHANGES

Confidence: medium

Summary: The core fix is correct and the root cause analysis is accurate. However, Tizen is left with the unfixed behavior, creating a cross-platform inconsistency. The test's hardcoded 600px drag distance is a fragility risk. These issues are straightforward to address and should be resolved before merge.


🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) Snapshot visible items before execution — .Where(GetIsVisible).ToList() to freeze list before loop ✅ PASS Android + iOS + Tizen MauiSwipeView.cs Preserves "all originally-visible items execute" semantics; also fixes Tizen
2 try-fix (claude-sonnet-4.6) Reentrancy guard (_isExecutingSwipeItems flag) + snapshot (ToList) — both guard and snapshot combined ✅ PASS Android + iOS + Tizen MauiSwipeView.cs Two-layer defense; also fixes Tizen
3 try-fix (gpt-5.3-codex) Initial-visibility gating — snapshot HashSet before loop, check membership before each ExecuteSwipeItem call ✅ PASS Android + iOS + Tizen MauiSwipeView.cs Per-item guard; also fixes Tizen
4 try-fix (gemini-3-pro-preview) BLOCKED — model unavailable BLOCKED gemini-3-pro-preview not in available models list
PR PR #35087 Replace foreach loop with FirstOrDefault(GetIsVisible) — execute only first visible item ✅ PASSED (Gate) Android + iOS MauiSwipeView.cs Original PR; Tizen not updated

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No "NO NEW IDEAS" — four approaches cover the solution space

Exhausted: Yes

Selected Fix: PR's fix — FirstOrDefault(GetIsVisible) is the semantically cleanest for Execute mode (one action per swipe), aligns with WinUI behavior, and Gate-confirmed working. All alternative approaches (attempts 1–3) also passed but with different semantics: they preserve "all originally-visible items execute" while also fixing Tizen. The PR's approach is simpler and more principled. Gap: all alternative approaches fixed Tizen which the PR missed — this gap should be noted in the report.


📋 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Issue #7580 — SwipeItem visibility toggle causes double command execution in Execute mode
Code Review NEEDS_CHANGES (medium) 0 errors, 3 warnings, 3 suggestions
Gate ✅ PASSED android
Try-Fix ✅ COMPLETE 3 attempts passing, 1 blocked (model unavailable); PR's fix selected
Report ✅ COMPLETE

Code Review Impact on Try-Fix

Code review's primary warning about Tizen not being updated directly shaped all three try-fix attempts: every model independently fixed Tizen as part of their alternative approach, confirming the omission is real and easy to address. The hardcoded test drag distance warning was consistent with an existing Copilot inline review comment, providing corroborating evidence. No model raised a fundamentally new concern not already in the code review.

Summary

PR #35087 fixes a genuine bug (issue #7580) where SwipeMode.Execute on Android/iOS would execute multiple SwipeItem commands if a command callback changed item visibility mid-iteration. The fix is correct and Gate-verified. However, two changes needed: (1) Tizen has the identical bug and was not fixed; (2) the UI test has a hardcoded endX = startX + 600 drag coordinate that can exceed device screen width.

Root Cause

In ValidateSwipeThreshold() on Android and iOS, a foreach loop iterates over all SwipeItems, calling ExecuteSwipeItem() for each visible one. If executing item A's command toggles item B from hidden to visible (or vice versa), B's new visibility state is evaluated within the same loop iteration, causing B to also execute — double-firing the command.

Fix Quality

The PR's FirstOrDefault(GetIsVisible) fix is elegant and principled: in SwipeMode.Execute, semantically only one item should execute per swipe (matching WinUI's native behavior). Three try-fix models confirmed the fix space with alternative snapshot/guard approaches, but all reviewers (including the prior Copilot inline review) agree on the PR's core logic.

Changes needed before merge:

  1. Apply the same fix to Tizen (src/Core/src/Platform/Tizen/MauiSwipeView.cs) — the identical foreach loop exists there and will cause the same double-execution bug on Tizen. All three passing try-fix attempts fixed Tizen as well.

  2. Fix the test drag distance in src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue7580.cs:28 — replace the hardcoded endX = startX + 600 with a device-relative calculation (e.g., rect.X + rect.Width - padding) or clamp to screen width to prevent flaky failures on small devices. This was flagged both by this code review and by a prior Copilot inline review.

The fix for issue #1 is 3 lines and straightforward. Issue #2 is a test quality improvement. Both are low-risk and the PR is otherwise well-structured with proper HostApp page and UI test.


@MauiBot MauiBot added the s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates label Apr 24, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current April 25, 2026 09:15
@kubaflo kubaflo merged commit 8ab3202 into dotnet:inflight/current Apr 25, 2026
28 of 37 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR7 milestone Apr 25, 2026
PureWeen pushed a commit that referenced this pull request Apr 28, 2026
…execution in Execute mode (#35087)

<!-- Please let the below note in for people that find this PR -->
   > [!NOTE]
   > Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
  Thank you!
 
### Root Cause
In `SwipeView` Execute mode, when a swipe crosses the threshold, the
framework iterates through all `SwipeItems` and executes the command for
each visible item. The visibility check is performed dynamically during
iteration. If the first item’s command changes the visibility of a
sibling item (for example, toggling a boolean that controls which
`SwipeItem` is shown), the newly visible item is also picked up and
executed within the same loop. This leads to a double invocation,
effectively cancelling the user’s intended action.
 
### Description of Change
Updated the Execute mode logic in `ValidateSwipeThreshold()` to execute
only the first visible `SwipeItem` using `FirstOrDefault(GetIsVisible)`,
instead of iterating through all items.

This change aligns Android and iOS with WinUI, where only one
`SwipeItem` is allowed in Execute mode at the platform level. It also
removes timing-related issues caused by UI updates during iteration and
prevents potential multiple executions when additional `SwipeItems` are
introduced in the future.
 
### Issues Fixed
Fixes #7580    
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Screenshots - Android
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/39fdad1f-cc24-4cca-9521-8c99e541c37b"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/c6112298-4723-49e6-84fe-cea1e5e8fe0a"
/> |

### Screenshots - iOS
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/f935ffa7-3b6e-4e06-8562-dc234d373b16"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/15711245-4d0d-4c16-9de8-edc7e442f5d9"
/> |
PureWeen pushed a commit that referenced this pull request Apr 29, 2026
…execution in Execute mode (#35087)

<!-- Please let the below note in for people that find this PR -->
   > [!NOTE]
   > Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
  Thank you!
 
### Root Cause
In `SwipeView` Execute mode, when a swipe crosses the threshold, the
framework iterates through all `SwipeItems` and executes the command for
each visible item. The visibility check is performed dynamically during
iteration. If the first item’s command changes the visibility of a
sibling item (for example, toggling a boolean that controls which
`SwipeItem` is shown), the newly visible item is also picked up and
executed within the same loop. This leads to a double invocation,
effectively cancelling the user’s intended action.
 
### Description of Change
Updated the Execute mode logic in `ValidateSwipeThreshold()` to execute
only the first visible `SwipeItem` using `FirstOrDefault(GetIsVisible)`,
instead of iterating through all items.

This change aligns Android and iOS with WinUI, where only one
`SwipeItem` is allowed in Execute mode at the platform level. It also
removes timing-related issues caused by UI updates during iteration and
prevents potential multiple executions when additional `SwipeItems` are
introduced in the future.
 
### Issues Fixed
Fixes #7580    
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Screenshots - Android
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/39fdad1f-cc24-4cca-9521-8c99e541c37b"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/c6112298-4723-49e6-84fe-cea1e5e8fe0a"
/> |

### Screenshots - iOS
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/f935ffa7-3b6e-4e06-8562-dc234d373b16"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/15711245-4d0d-4c16-9de8-edc7e442f5d9"
/> |
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
…execution in Execute mode (#35087)

<!-- Please let the below note in for people that find this PR -->
   > [!NOTE]
   > Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
  Thank you!
 
### Root Cause
In `SwipeView` Execute mode, when a swipe crosses the threshold, the
framework iterates through all `SwipeItems` and executes the command for
each visible item. The visibility check is performed dynamically during
iteration. If the first item’s command changes the visibility of a
sibling item (for example, toggling a boolean that controls which
`SwipeItem` is shown), the newly visible item is also picked up and
executed within the same loop. This leads to a double invocation,
effectively cancelling the user’s intended action.
 
### Description of Change
Updated the Execute mode logic in `ValidateSwipeThreshold()` to execute
only the first visible `SwipeItem` using `FirstOrDefault(GetIsVisible)`,
instead of iterating through all items.

This change aligns Android and iOS with WinUI, where only one
`SwipeItem` is allowed in Execute mode at the platform level. It also
removes timing-related issues caused by UI updates during iteration and
prevents potential multiple executions when additional `SwipeItems` are
introduced in the future.
 
### Issues Fixed
Fixes #7580    
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Screenshots - Android
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/39fdad1f-cc24-4cca-9521-8c99e541c37b"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/c6112298-4723-49e6-84fe-cea1e5e8fe0a"
/> |

### Screenshots - iOS
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/f935ffa7-3b6e-4e06-8562-dc234d373b16"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/15711245-4d0d-4c16-9de8-edc7e442f5d9"
/> |
github-actions Bot pushed a commit that referenced this pull request May 25, 2026
…execution in Execute mode (#35087)

<!-- Please let the below note in for people that find this PR -->
   > [!NOTE]
   > Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
  Thank you!
 
### Root Cause
In `SwipeView` Execute mode, when a swipe crosses the threshold, the
framework iterates through all `SwipeItems` and executes the command for
each visible item. The visibility check is performed dynamically during
iteration. If the first item’s command changes the visibility of a
sibling item (for example, toggling a boolean that controls which
`SwipeItem` is shown), the newly visible item is also picked up and
executed within the same loop. This leads to a double invocation,
effectively cancelling the user’s intended action.
 
### Description of Change
Updated the Execute mode logic in `ValidateSwipeThreshold()` to execute
only the first visible `SwipeItem` using `FirstOrDefault(GetIsVisible)`,
instead of iterating through all items.

This change aligns Android and iOS with WinUI, where only one
`SwipeItem` is allowed in Execute mode at the platform level. It also
removes timing-related issues caused by UI updates during iteration and
prevents potential multiple executions when additional `SwipeItems` are
introduced in the future.
 
### Issues Fixed
Fixes #7580    
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Screenshots - Android
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/39fdad1f-cc24-4cca-9521-8c99e541c37b"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/c6112298-4723-49e6-84fe-cea1e5e8fe0a"
/> |

### Screenshots - iOS
| Before Issue Fix | After Issue Fix |
|------------------|-----------------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/f935ffa7-3b6e-4e06-8562-dc234d373b16"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/15711245-4d0d-4c16-9de8-edc7e442f5d9"
/> |
@github-actions github-actions Bot locked and limited conversation to collaborators May 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-swipeview SwipeView community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Changing visibility on an SwipeItem causes multiple items to be executed

5 participants