Fix SwipeView.Open() crash on second call (iOS/MacCatalyst)#34983
Fix SwipeView.Open() crash on second call (iOS/MacCatalyst)#34983StephaneDelcroix wants to merge 1 commit intomainfrom
Conversation
Clear stale _swipeItems dictionary entries and remove old _actionView in UpdateSwipeItems() before creating new ones. The Swipe() method could set _isOpen = false without calling DisposeSwipeItems(), leaving stale entries in _swipeItems. The next Open() call would then attempt to add duplicate keys, causing an ArgumentException. Fixes #34917 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34983Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34983" |
There was a problem hiding this comment.
Pull request overview
Fixes an iOS/MacCatalyst crash when calling SwipeView.Open() multiple times by making the iOS MauiSwipeView.UpdateSwipeItems() path safe to re-enter, and adds a regression UI test for the scenario.
Changes:
- Clear stale swipe-item state in
MauiSwipeView.UpdateSwipeItems()before rebuilding native swipe-item views. - Add HostApp repro page
Issue34917with buttons to open/close aSwipeViewprogrammatically. - Add an Appium/NUnit UI test
Issue34917that opens, closes, then opens again to validate no crash.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Core/src/Platform/iOS/MauiSwipeView.cs | Clears prior swipe-item cache/view before rebuilding to avoid duplicate-key crashes on repeated Open(). |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34917.cs | Adds UI test validating repeated programmatic open does not crash. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue34917.cs | Adds HostApp issue page used by the UI test to reproduce the scenario. |
| App.WaitForElement("StatusLabel"); | ||
| var status1 = App.FindElement("StatusLabel").GetText(); | ||
| Assert.That(status1, Is.EqualTo("Opened 1"), "First Open should succeed"); | ||
|
|
| App.Tap("CloseButton"); | ||
|
|
||
| // Wait for close animation | ||
| Task.Delay(500).Wait(); | ||
|
|
||
| // Second open - this used to crash with ArgumentException | ||
| App.Tap("OpenButton"); | ||
| var status2 = App.FindElement("StatusLabel").GetText(); | ||
| Assert.That(status2, Is.EqualTo("Opened 2"), "Second Open should succeed without crash"); |
| @@ -0,0 +1,87 @@ | |||
| namespace Maui.Controls.Sample.Issues; | |||
|
|
|||
| [Issue(IssueTracker.Github, 34917, "SwipeView.Open crashes with ArgumentException on second call", PlatformAffected.iOS)] | |||
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
…, security hardening (#34678) ## Description Overhauls the `copilot-evaluate-tests` gh-aw workflow — switches to on-demand triggers only (`/evaluate-tests` slash command + manual `workflow_dispatch`), adds security hardening, and improves error handling. No auto-runs on PR create/update. ### What Changed **Triggers (on-demand only — no auto-runs)** - Add `slash_command: evaluate-tests` — comment `/evaluate-tests` on a PR to trigger - Keep `workflow_dispatch` — manual trigger from Actions tab with PR number input - Disable `pull_request_target` — no auto-evaluation on PR create/update - Add `bots: ["copilot-swe-agent[bot]"]` — Copilot-authored PRs can be evaluated - Add `labels: ["pr-review", "testing"]` — workflow runs are labeled **Gate step (fast-fail for invalid requests)** - Check PR is OPEN before evaluating (rejects closed/merged PRs with clear message) - Check for test source files in diff before spinning up agent - Fall back to REST API for PRs with 300+ files (where `gh pr diff` returns HTTP 406) - All API errors surfaced with clear messages — no silent masking - `exit 1` stops the workflow immediately — no wasted agent compute **Access gating (`Checkout-GhAwPr.ps1`)** - Reject fork PRs (`isCrossRepository` check) - Verify PR author has write access (admin/write/maintain roles) - Fix `ConvertFrom-Json` ordering — check exit code before JSON parsing - Make infrastructure restore fatal on failure (was soft warning) - Remove pre-delete pattern — `git checkout` overwrites in-place **Workflow improvements** - `hide-older-comments: true` — previous evaluations auto-collapse - `report-as-issue: false` for noop — no issue created when nothing to evaluate - Timeout bumped 15 → 20 minutes - Dry-run mode via `suppress_output` input (workflow_dispatch only) - `Gather-TestContext.ps1` now receives `-PrNumber` parameter **Security documentation (`gh-aw-workflows.instructions.md`)** - Add "Before You Build" anti-patterns table — prefer built-in gh-aw features - Add Security Boundaries section with defense layers table - Add Rules for gh-aw Workflow Authors (DO/DON'T list) - Document `COPILOT_TOKEN` exposure and mitigations - Add `slash_command` to fork behavior table - Update `Checkout-GhAwPr.ps1` description to match current behavior ### Trigger Behavior | Trigger | When it fires | Who can trigger | |---------|---------------|-----------------| | `/evaluate-tests` comment | Comment on a PR | Write-access collaborators + copilot-swe-agent[bot] | | `workflow_dispatch` | Actions tab → "Run workflow" → enter PR number | Write-access collaborators | | ~~`pull_request_target`~~ | ~~Auto on PR create/update~~ | ~~Disabled~~ | ### Security Model Based on [GitHub Security Lab guidance](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/): - PR contents treated as **passive data** (read/analyze, never built or executed) - Agent runs in **sandboxed container** with `GITHUB_TOKEN` and `gh` CLI scrubbed - Write operations in **separate `safe_outputs` job** (not the agent) - Agent output limited to `max: 1` comment via safe-outputs - `Checkout-GhAwPr.ps1` rejects fork PRs and verifies write access before checkout - Infrastructure restore is fatal on failure — prevents running with untrusted infra ### Validation | Test | PR | Result | |------|-----|--------| | Open PR with tests | #34983 | ✅ Full success (gate → checkout → agent → comment) | | No-test PR | #34876 | ✅ Gate fast-fail ("no test source files") | | Merged PR | #34932 | ✅ Gate fast-fail ("MERGED — skipping") | ### Known Limitations - Fork PRs via `/evaluate-tests` can supply modified `.github/skills/` — accepted residual risk (agent sandboxed, output bounded). Tracked as [gh-aw#18481](github/gh-aw#18481) - `exit 1` in gate step shows ❌ in GitHub checks for no-test/closed PRs — intentional (no built-in "skip" mechanism in gh-aw steps) - `pull_request_target` commented out — can be re-enabled later for auto-evaluation --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🚦 Gate — Test Before and After Fix
🚦 Gate Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue34917 Issue34917 |
❌ PASS — 217s | ✅ PASS — 91s |
🔴 Without fix — 🖥️ Issue34917: PASS ❌ · 217s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 565 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 601 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 10.37 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 10.65 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 10.65 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 10.65 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 10.66 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 10.69 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 10.68 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 10.72 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 10.72 sec).
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Detected signing identity:
Code Signing Key: "" (-)
Provisioning Profile: "" () - no entitlements
Bundle Id: com.microsoft.maui.uitests
App Id: com.microsoft.maui.uitests
Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
Optimizing assemblies for size. This process might take a while.
Build succeeded.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
1 Warning(s)
0 Error(s)
Time Elapsed 00:01:45.17
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 791 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 791 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 791 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 791 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 1 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 814 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 882 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 900 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.63 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 1.91 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.54 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 3.77 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 4.61 sec).
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.05] Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.14] Discovered: Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 4/15/2026 12:28:53 PM FixtureSetup for Issue34917(iOS)
>>>>> 4/15/2026 12:28:56 PM SwipeViewOpenDoesNotCrashOnSecondCall Start
>>>>> 4/15/2026 12:28:59 PM SwipeViewOpenDoesNotCrashOnSecondCall Stop
Passed SwipeViewOpenDoesNotCrashOnSecondCall [2 s]
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Successful.
Total tests: 1
Passed: 1
Total time: 1.0444 Minutes
🟢 With fix — 🖥️ Issue34917: PASS ✅ · 91s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 403 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 418 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 424 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 456 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 472 ms).
6 of 11 projects are up-to-date for restore.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
Detected signing identity:
Code Signing Key: "" (-)
Provisioning Profile: "" () - no entitlements
Bundle Id: com.microsoft.maui.uitests
App Id: com.microsoft.maui.uitests
Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
Optimizing assemblies for size. This process might take a while.
Build succeeded.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:44.46
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 396 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 394 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 398 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 413 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 427 ms).
8 of 13 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13847096
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.05] Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.18] Discovered: Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 4/15/2026 12:30:23 PM FixtureSetup for Issue34917(iOS)
>>>>> 4/15/2026 12:30:27 PM SwipeViewOpenDoesNotCrashOnSecondCall Start
>>>>> 4/15/2026 12:30:30 PM SwipeViewOpenDoesNotCrashOnSecondCall Stop
Passed SwipeViewOpenDoesNotCrashOnSecondCall [2 s]
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Successful.
Total tests: 1
Passed: 1
Total time: 19.9009 Seconds
⚠️ Issues found
- ❌ Issue34917 PASSED without fix (should fail) — tests don't catch the bug
📁 Fix files reverted (1 files)
src/Core/src/Platform/iOS/MauiSwipeView.cs
🤖 AI Summary
📊 Review Session —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34983 | _swipeItems.Clear() + _actionView?.RemoveFromSuperview() at start of UpdateSwipeItems() |
✅ PASSED (with fix) / ❌ PASS without fix (Gate FAILED) | MauiSwipeView.cs |
Defensive/idempotent approach |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | in + DispatchDelayed(50ms) test | PASS | MauiSwipeView.cs, Issue34917.cs (x2) |
Targeted fix at crash site; missing _actionView cleanup |
| 2 | try-fix (claude-sonnet-4.6) | Root cause in : + DispatchDelayed(50ms) test | PASS | MauiSwipeView.cs, Issue34917.cs (x2) |
Prevents stale state creation; only clears dict, not _actionView |
| 3 | try-fix (gpt-5.3-codex) | Replace with indexer + before rebuild | PASS | MauiSwipeView.cs, Issue34917.cs (x2) |
Avoids exception at call site; handles both dict and view leak |
| closed only (`wasOpen && !_ FAIL | MauiSwipeView.cs, Issue34917.cs (x2) |
Missed back-to-back case: stale state from first Open() before animation fires | isOpen`) | ||
| 5 | try-fix (claude-opus-4.6) | only sets , never false; owns false transition | PASS | MauiSwipeView.cs, Issue34917.cs (x2) |
Elegant ownership semantics; may affect gesture timing window |
| 6 | try-fix (gpt-5.3-codex) | Reentrancy guard + transactional swap in | PASS | MauiSwipeView.cs, Issue34917.cs (x2) |
Most complex; adds new field; overkill for this bug |
| PR | PR #34983 | + at start of | With Gate FAILED | MauiSwipeView.cs |
Defensive/idempotent; correct production fix; test is the problem |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| ran as Attempt 5 | |||
| claude-sonnet-4.6 | 2 | No | NO NEW IDEAS |
| ran as Attempt 6 | |||
| gpt-5.4 | 2 | No | NO NEW IDEAS |
| claude-opus-4.6 | 3 | No | NO NEW solution space exhausted |
Exhausted: Yes
Selected Fix: PR's production fix is CORRECT + test needs to be rewritten. The PR's _swipeItems.Clear() + _actionView?.RemoveFromSuperview() at start of UpdateSwipeItems() is the cleanest: idempotent, handles both concerns, minimal change. Gate FAILED only because Task.Delay(500).Wait() masks the bug. Test must use DispatchDelayed(50ms) + WaitForElement-based assertions.
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #34917, iOS/MacCatalyst, 1 impl + 2 test files |
| Gate | ❌ FAILED | iOS — test PASSED without fix (bug masked by Task.Delay) |
| Try-Fix | ✅ COMPLETE | 6 attempts (5 passing, 1 failing); exhausted after 3 cross-pollination rounds |
| Report | ✅ COMPLETE |
Summary
PR #34983 contains a correct production fix for SwipeView.Open() crashing on second call with ArgumentException on iOS/MacCatalyst. However, the Gate FAILED because the test passes even without the fix — Task.Delay(500).Wait() allows the close animation to complete and call DisposeSwipeItems(), which clears the dictionary before the second Open(), masking the bug entirely. Three unresolved inline review comments also remain unaddressed.
Selected Fix: PR's production fix is correct. The test needs to be fixed to reliably demonstrate the bug.
Root Cause
In MauiSwipeView.cs, the Swipe() method sets _isOpen = offset != 0. During the close animation, when the content reaches offset=0, _isOpen becomes false but DisposeSwipeItems() is only called in the animation completion callback (~200ms later). During this window, if Open() is called again:
_isOpen == false→ guard inProgrammaticallyOpenSwipeItemis skippedUpdateSwipeItems()is called_swipeItems.Add(item, swipeItem)throwsArgumentExceptionbecause dictionary already contains keys from the first open
Fix Quality
Production fix (MauiSwipeView.cs): ✅ CORRECT and COMPLETE
_swipeItems.Clear()+_actionView?.RemoveFromSuperview()at the start ofUpdateSwipeItems()makes the method idempotent- Handles both the dictionary duplicate-key issue AND the stale
_actionViewview hierarchy concern - Minimal, defensive, and consistent with existing patterns in the codebase
- 5 out of 6 independent try-fix attempts also passed with this general approach
Test quality: ❌ REQUIRES CHANGES — 3 issues:
-
Task.Delay(500).Wait()masks the bug (line 36 of test): The 500ms delay allows the close animation's completion callback to runDisposeSwipeItems(), clearing the stale state before the second Open(). This means the test passes even without the fix. Replace withDispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(50), () => swipeView.Open(...))in the HostApp and useApp.WaitForElement(e => e.GetText() == "Opened 2")in the test. -
App.WaitForElement("StatusLabel")races UI update (line 26):StatusLabelis always present; this does not wait for the text to update. Replace with a wait for the specific text value (e.g.,App.WaitForTextToBePresentInElement("StatusLabel", "Opened 1")). -
PlatformAffected.iOSmisses MacCatalyst (HostApp line 3): The issue affects both iOS and MacCatalyst per the bug report ([net 11.0][iOS,MacCatalyst] SwipeView.Open() throws ArgumentException on second programmatic call #34917) and PR title. Should bePlatformAffected.iOS | PlatformAffected.macOSor equivalent.
Required Changes
// HostApp: Issue34917.cs
// Replace the Clicked handler — trigger re-open mid-animation (50ms after close starts)
closeButton.Clicked += (s, e) =>
{
swipeView.Close();
statusLabel.Text = "Closed";
- // No delay needed in HostApp — test should drive timing
+ Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(50), () =>
+ {
+ try
+ {
+ openCount++;
+ swipeView.Open(OpenSwipeItem.LeftItems);
+ statusLabel.Text = $"Opened {openCount}";
+ }
+ catch (Exception ex)
+ {
+ statusLabel.Text = $"Error: {ex.GetType().Name}";
+ }
+ });
};
// Test: Issue34917.cs
- App.WaitForElement("StatusLabel");
- var status1 = App.FindElement("StatusLabel").GetText();
+ var status1 = App.WaitForTextToBePresentInElement("StatusLabel", "Opened 1");
- Task.Delay(500).Wait();
- App.Tap("OpenButton");
- var status2 = App.FindElement("StatusLabel").GetText();
+ App.Tap("CloseButton");
+ // Wait for re-open triggered by DispatchDelayed in HostApp
+ App.WaitForTextToBePresentInElement("StatusLabel", "Opened 2", TimeSpan.FromSeconds(5));
// HostApp: Issue34917.cs — line 3
- [Issue(IssueTracker.Github, 34917, "...", PlatformAffected.iOS)]
+ [Issue(IssueTracker.Github, 34917, "...", PlatformAffected.iOS | PlatformAffected.macOS)]Try-Fix Winner Comparison
| Approach | Simplicity | Completeness | Risk |
|---|---|---|---|
| PR fix (UpdateSwipeItems idempotent) | ✅ 2 lines | ✅ Handles dict + view | ✅ Low |
| Attempt 3 (indexer + remove) | ✅ Similar | ✅ Handles dict + view | ✅ Low |
| Attempt 5 (_isOpen ownership) | ✅ 1 line | ||
| Attempt 6 (reentrancy guard) | ❌ Complex | ✅ Most defensive |
PR's fix is the recommended production approach. The test is the blocker.
|
@StephaneDelcroix, I have already fixed this issue. Please find the below-mentioned PR for your reference. PR link: #34982 I also reviewed the changes in this PR. It clears _swipeItems and resolves the crash. However, it adds _actionView?.RemoveFromSuperview() in UpdateSwipeItems(), which removes the swipe items view from the hierarchy before recreating it. This introduces a regression where the SwipeView closes immediately after being opened programmatically. Please refer to the video below.
|
|
Closing in favour of #34982 |
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!
Description
Fixes #34917
Calling
SwipeView.Open()a second time on iOS/MacCatalyst crashes withSystem.ArgumentException: An item with the same key has already been added.Root Cause
In
MauiSwipeView.cs, theSwipe()method (line 584) sets_isOpen = offset != 0, which can transition_isOpentofalsewithout callingDisposeSwipeItems(). This leaves stale entries in the_swipeItemsdictionary. WhenOpen()is called again:_isOpenisfalse, so the guard inProgrammaticallyOpenSwipeItemis skippedUpdateSwipeItems()is called_swipeItems.Add(item, swipeItem)throwsArgumentExceptionbecause the dictionary already contains keys from the previous openFix
Clear the
_swipeItemsdictionary and remove the old_actionViewfrom the superview at the start ofUpdateSwipeItems(), before creating new swipe item views. This makes the method idempotent — safe to call regardless of prior state.Testing
Added UI test (
Issue34917) that opens a SwipeView, closes it, then opens it again — verifying no crash occurs on the second open.