[net11.0] Add opt-in Move support to drag and drop - #39016
Conversation
Co-authored-by: Copilot App <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 -- 39016Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 39016" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
Skill Validation Results
✅ Skill Validation Results —
|
This comment has been minimized.
This comment has been minimized.
|
/azp run |
|
Azure Pipelines: Successfully started running 3 pipeline(s). |
|
Note 🔍
|
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Cross-platform build, device, and UI pipelines remain pending for this Apple platform behavior change.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds opt-in drag-and-drop Move support across the shared API, Apple implementation, and platform samples.
Changes:
- Adds
DataPackageOperation.Movewith API documentation. - Maps accepted operations to native iOS/Mac Catalyst proposals.
- Adds unit/device coverage and updates Windows/iOS samples.
| File | Description |
|---|---|
src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs |
Tests Apple proposal selection and recognizer behavior. |
src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs |
Tests enum flags and accepted-operation handling. |
src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt |
Declares the new API. |
src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt |
Declares the new API. |
src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt |
Declares the Windows API. |
src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt |
Declares the Tizen API. |
src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt |
Declares the Mac Catalyst API. |
src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt |
Declares the iOS API. |
src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt |
Declares the Android API. |
src/Controls/src/Core/Platform/iOS/DragAndDropDelegate.cs |
Maps aggregated acceptance to Copy, Move, or Cancel. |
src/Controls/src/Core/DragAndDrop/DragEventArgs.cs |
Documents platform negotiation behavior. |
src/Controls/src/Core/DragAndDrop/DataPackageOperation.cs |
Adds the Move flag. |
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xaml.cs |
Configures native Windows Move permissions. |
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xaml |
Adds the Move sample control and event hookup. |
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSDragAndDropRequestFullSize.xaml.cs |
Uses shared Move acceptance on Apple platforms. |
| e.PlatformArgs!.SetDropProposal(new UIKit.UIDropProposal(UIKit.UIDropOperation.Copy)); | ||
| else if (moveSwitch.IsToggled) | ||
| e.PlatformArgs!.SetDropProposal(new UIKit.UIDropProposal(UIKit.UIDropOperation.Move)); | ||
| e.AcceptedOperation = DataPackageOperation.Move; |
|
Dang, paying my respect. That was fast :D |
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@jfversluis — new AI review results are available based on commit
5d52529.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ⚠️ INCONCLUSIVE
Platform: IOS · Base: net11.0 · Merge base: 528f519a
🩺 Could not verify — environment/infrastructure error. The gate ran the tests but hit an environment error (an emulator/simulator/Appium/XHarness flake, a device that would not boot, or an empty/invalid result file), so it could not record a real pass/fail. The /review to retry on a fresh agent.
XHarness did not produce the expected fresh result 'testResults.xml' for requested class(es) 'Microsoft.Maui.DeviceTests.DragAndDropTests' (the target tests did not run).
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🧪 DropGestureRecognizerTests DropGestureRecognizerTests |
🛠️ BUILD ERROR | ✅ PASS — 23s |
📱 DragAndDropTests (SessionDidUpdateDefaultsToCopy, SessionDidUpdateRoutesAcceptedOperation, SessionDidUpdateWithoutDropRecognizerCancels, SessionDidUpdateSkipsDisabledDropRecognizer, SessionDidUpdateHonorsCustomProposalOnlyWhenAccepted, SessionDidUpdateCombinesRecognizerAcceptance, SessionDidUpdateDoesNotRetainPreviousAcceptance, SessionDidUpdateDoesNotRetainPreviousCustomProposal, SessionDidUpdateReevaluatesChangedRecognizers, SessionDidUpdatePreservesAcceptanceThroughPassiveRecognizer) Category=Gesture |
🛠️ BUILD ERROR |
🔴 Without fix — 🧪 DropGestureRecognizerTests: 🛠️ BUILD ERROR · 20s
Error-relevant lines (filtered from the build log):
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs(39,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs(40,64): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs(54,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs(55,64): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
🟢 With fix — 🧪 DropGestureRecognizerTests: PASS ✅ · 23s
(no coded error found; showing last 1200 chars)
ompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.Entry), result: "EntryTest") [< 1 ms]
Passed TextPackageCorrectlySetsOnCompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.TimePicker), result: "01:00:00") [< 1 ms]
Passed TextPackageCorrectlySetsOnCompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.RadioButton), result: "True") [1 ms]
Passed TextPackageCorrectlySetsOnCompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.Label), result: "LabelTest") [< 1 ms]
Passed TextPackageCorrectlySetsOnCompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.Editor), result: "EditorTest") [< 1 ms]
Passed DragOverDefaultsToCopy [< 1 ms]
[xUnit.net 00:00:00.85] Finished: Microsoft.Maui.Controls.Core.UnitTests
Passed DateTextPackageCorrectlySetsOnCompatibleTarget(fieldType: typeof(Microsoft.Maui.Controls.DatePicker), result: "12/12/2020 12:00:00 AM") [2 ms]
Passed SendDropThrowsSynchronouslyForNullArgs [< 1 ms]
Passed DropCommandFires [1 ms]
Passed DataPackageOperationsAreIndependentFlags [1 ms]
Passed PropertySetters [< 1 ms]
Passed DragOverCommandFires [< 1 ms]
Test Run Successful.
Total tests: 24
Passed: 24
Total time: 1.0841 Seconds
🔴 Without fix — 📱 DragAndDropTests (SessionDidUpdateDefaultsToCopy, SessionDidUpdateRoutesAcceptedOperation, SessionDidUpdateWithoutDropRecognizerCancels, SessionDidUpdateSkipsDisabledDropRecognizer, SessionDidUpdateHonorsCustomProposalOnlyWhenAccepted, SessionDidUpdateCombinesRecognizerAcceptance, SessionDidUpdateDoesNotRetainPreviousAcceptance, SessionDidUpdateDoesNotRetainPreviousCustomProposal, SessionDidUpdateReevaluatesChangedRecognizers, SessionDidUpdatePreservesAcceptanceThroughPassiveRecognizer): 🛠️ BUILD ERROR · 40s
Error-relevant lines (filtered from the build log):
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(41,64): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(102,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(103,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(104,64): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(139,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(140,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(142,63): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(143,63): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(144,63): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(145,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(226,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(268,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj::TargetFramework=net11.0-ios]
Build FAILED.
🟢 With fix — 📱 DragAndDropTests (SessionDidUpdateDefaultsToCopy, SessionDidUpdateRoutesAcceptedOperation, SessionDidUpdateWithoutDropRecognizerCancels, SessionDidUpdateSkipsDisabledDropRecognizer, SessionDidUpdateHonorsCustomProposalOnlyWhenAccepted, SessionDidUpdateCombinesRecognizerAcceptance, SessionDidUpdateDoesNotRetainPreviousAcceptance, SessionDidUpdateDoesNotRetainPreviousCustomProposal, SessionDidUpdateReevaluatesChangedRecognizers, SessionDidUpdatePreservesAcceptanceThroughPassiveRecognizer): ⚠️ ENV ERROR · 61s
No log file found
⚠️ Failure Details
- 🛠️ DropGestureRecognizerTests without fix: build failed before tests could run
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Gestures/DropGestureRecognizerTests.cs(39,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users/cl...
- 🛠️ DragAndDropTests (SessionDidUpdateDefaultsToCopy, SessionDidUpdateRoutesAcceptedOperation, SessionDidUpdateWithoutDropRecognizerCancels, SessionDidUpdateSkipsDisabledDropRecognizer, SessionDidUpdateHonorsCustomProposalOnlyWhenAccepted, SessionDidUpdateCombinesRecognizerAcceptance, SessionDidUpdateDoesNotRetainPreviousAcceptance, SessionDidUpdateDoesNotRetainPreviousCustomProposal, SessionDidUpdateReevaluatesChangedRecognizers, SessionDidUpdatePreservesAcceptanceThroughPassiveRecognizer) without fix: build failed before tests could run
/Users/cloudtest/vss/_work/1/s/src/Controls/tests/DeviceTests/Elements/DragAndDrop/DragAndDropTests.iOS.cs(38,36): error CS0117: 'DataPackageOperation' does not contain a definition for 'Move' [/Users...
⚠️ DragAndDropTests (SessionDidUpdateDefaultsToCopy, SessionDidUpdateRoutesAcceptedOperation, SessionDidUpdateWithoutDropRecognizerCancels, SessionDidUpdateSkipsDisabledDropRecognizer, SessionDidUpdateHonorsCustomProposalOnlyWhenAccepted, SessionDidUpdateCombinesRecognizerAcceptance, SessionDidUpdateDoesNotRetainPreviousAcceptance, SessionDidUpdateDoesNotRetainPreviousCustomProposal, SessionDidUpdateReevaluatesChangedRecognizers, SessionDidUpdatePreservesAcceptanceThroughPassiveRecognizer) with fix:XHarness did not produce the expected fresh result 'testResults.xml' for requested class(es) 'Microsoft.Maui.DeviceTests.DragAndDropTests' (the target tests did not run).
📁 Fix files reverted (13 files)
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xamlsrc/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xaml.cssrc/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSDragAndDropRequestFullSize.xaml.cssrc/Controls/src/Core/DragAndDrop/DataPackageOperation.cssrc/Controls/src/Core/DragAndDrop/DragEventArgs.cssrc/Controls/src/Core/Platform/iOS/DragAndDropDelegate.cssrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
📋 Pre-Flight — Context & Validation
Issue: #16472 - Add DataPackageOperation.Move option for Drag & Drop
PR: #39016 - [net11.0] Add opt-in Move support to drag and drop
Base / Head: net11.0 / squashed review commit 8501e991cb08e71d1df14761c14e66bd5059b53d
Platforms Affected: iOS and Mac Catalyst implementation; shared public API on all TFMs; Windows sample negotiation
Files Changed: 13 implementation/API/sample files, 2 test files
Problem and Existing PR Approach
The shared drag-and-drop API exposes only None and Copy, so a drop target cannot request a native move proposal. The PR adds the [Flags] value DataPackageOperation.Move = 2, documents application-owned source-data updates, and records the API for every target framework.
On Apple platforms, the PR changes HandleDragOver from a Boolean validity result to an aggregate DataPackageOperation. SessionDidUpdate preserves an explicit native proposal when any shared operation is accepted; otherwise it prefers Copy, proposes Move only for move-only acceptance when IUIDropSession.AllowsMoveOperation is true, and returns Cancel for unsupported/rejected operations. It deliberately preserves default Copy behavior and combines acceptance across enabled recognizers.
Key Findings
src/Controls/src/Core/Platform/iOS/DragAndDropDelegate.csis the runtime path for both iOS and Mac Catalyst.- The PR reuses one
DragEventArgswhile visiting enabledDropGestureRecognizerinstances and ORs each post-callbackAcceptedOperation; passive recognizers therefore preserve prior acceptance. - Native Move is gated by
session.AllowsMoveOperation;Copy | Moveprefers Copy. - A custom
PlatformDragEventArgs.DropProposaltakes precedence only when aggregate shared acceptance is non-None. - Existing supported
NoneandCopysemantics are intended to remain unchanged. Undefined numeric enum values may now cancel instead of falling back to Copy. - Public review feedback identified one low-severity sample mismatch: the iOS sample XAML still labels the scenario “UIDropProposal - Move” although its code now demonstrates shared
AcceptedOperation. - The prior Gate is INCONCLUSIVE, not a product failure: the focused unit tests passed with the PR, while the iOS device runner did not emit a fresh
testResults.xml. Gate verification must not be rerun in STEP 5a. - Regression cross-reference found same-file overlap with #34885 but no exact reverted lines.
Code Review Summary
Verdict: SKIPPED
Confidence: N/A
Errors: 0 | Warnings: 0 | Suggestions: 0
The dedicated expert pass is deferred to STEP 5b by the hard execution contract. No pre-flight expert-review agent was launched.
Test Contract for Try-Fix
Platform: ios
Primary regression test:
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "Category=Gesture"This covers the added DragAndDropTests cases for default Copy, Move gating, combined recognizer acceptance, custom proposal precedence, disabled/missing recognizers, per-update reset, and recognizer replacement.
Mandatory focused regression test:
dotnet test src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj --filter "FullyQualifiedName~DropGestureRecognizerTests"Do not run the Gate workflow or any full suite. Each candidate may run one implementation/test pass and at most one focused correction/retest.
Baseline Modification Allow-List
The prior Gate identified these 13 fix files. EstablishBrokenBaseline.ps1 is authoritative; after baseline creation, edit only paths listed in .github/.baseline-state.json under RevertedFiles.
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xamlsrc/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/Windows/WindowsDragAndDropCustomization.xaml.cssrc/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSDragAndDropRequestFullSize.xaml.cssrc/Controls/src/Core/DragAndDrop/DataPackageOperation.cssrc/Controls/src/Core/DragAndDrop/DragEventArgs.cssrc/Controls/src/Core/Platform/iOS/DragAndDropDelegate.cssrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #39016 | Aggregate shared accepted-operation flags in the Apple delegate, prefer Copy, and gate native Move on session permission | 13 implementation/API/sample files | Unit tests passed; iOS device execution was blocked by missing fresh XHarness results |
🔬 Code Review — Deep Analysis
Expert PR Evaluation
Verdict: NEEDS_DISCUSSION
Confidence: low
The submitted fix coherently adds DataPackageOperation.Move and maps shared acceptance to Apple-native proposals. The implementation aggregates enabled DropGestureRecognizer acceptance, preserves an explicit native DropProposal, prefers Copy for Copy | Move, and proposes Move only when the drop session allows it. The added unit and iOS device-test coverage exercises the principal aggregation, proposal-precedence, state-reset, recognizer lifecycle, and Move-permission paths.
No actionable error or warning was found on an added or modified line, and no unresolved prior error-level review finding was identified. The raw inline findings artifact is therefore an empty JSON array.
The review cannot recommend approval yet because the trusted Gate is inconclusive and current required-check coverage could not be established as passing. This is an evidence limitation, not a test failure or a code defect. One non-blocking refinement remains available: the Apple sample still labels the scenario UIDropProposal - Move even though the updated sample demonstrates shared DragEventArgs.AcceptedOperation acceptance.
🛠️ Try-Fix — Analysis & Comparison
STEP 5a Try-Fix Aggregate
PR: #39016
Platform: iOS
Bound: At most two candidates, each with one implementation/test pass and at most one focused correction/retest.
Candidate 1 — Session-Aware Single Effective Acceptance
Model: gpt-5.3-codex
Result:
Candidate narrative: ../try-fix-1/content.md
Attempt artifacts: attempt-1/
Approach
Resolve one authoritative effective acceptance per update, honoring a custom native proposal first and otherwise mapping that acceptance through IUIDropSession.AllowsMoveOperation, rather than OR-aggregating flags across recognizers as the PR does.
Mechanism-Level Difference
The PR accumulates every recognizer's post-callback flags and derives the native proposal from that combined bitmask. Candidate 1 instead proposed preventing cross-recognizer accumulation from selecting the native operation by resolving a single effective acceptance for the update.
Diff
No candidate diff was produced.
Test Results
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "Category=Gesture"— not rundotnet test src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj --filter "FullyQualifiedName~DropGestureRecognizerTests"— not run
Failure Analysis
EstablishBrokenBaseline.ps1 rejected eight pre-existing tracked modifications outside the PR fix allow-list, and .github/.baseline-state.json was not created. The skill therefore prohibited edits or tests. Inline self-review recorded zero findings against the empty candidate diff. The exact mandatory restore command ran and reported No baseline state found / Restored=False, which is valid for this no-state/no-edit blocked path.
Candidate 2
Model: gpt-5.6-sol
Result:
Candidate narrative: ../try-fix-2/content.md
Attempt artifacts: attempt-2/
Approach
No runtime approach was designed or applied. Candidate 2 followed the required no-edit path because the authoritative baseline could not be established.
Mechanism-Level Difference
Candidate 2 implemented neither the PR's aggregate-flags mechanism nor candidate 1's planned single-effective-acceptance mechanism. Its only executed mechanism was the try-fix skill's fail-closed baseline guard; therefore it provides no runtime alternative or behavioral evidence.
Diff
No candidate diff was produced.
Test Results
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "Category=Gesture"— not rundotnet test src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj --filter "FullyQualifiedName~DropGestureRecognizerTests"— not run
Failure Analysis
EstablishBrokenBaseline.ps1 again rejected the same eight unrelated pre-existing tracked modifications and did not create .github/.baseline-state.json. Editing without the resulting RevertedFiles allow-list would violate the try-fix restoration contract, so the attempt stopped before target-file analysis, design, implementation, or testing. Inline self-review recorded zero findings against the empty candidate diff. The exact mandatory restore command ran and reported No baseline state found / Restored=False, valid for the verified no-state/no-edit blocked path.
Aggregate Outcome
Two child invocations were run sequentially in the required model order. Both are BLOCKED by the same environment state, not failed fixes. No product, API, sample, test, Gate, candidate-1, or pre-existing untracked files were modified by either attempt; both captured empty diffs and skipped tests because no safely restorable baseline existed.
The blocking tracked paths are:
.github/scripts/CopilotPipeline.Tests.ps1.github/scripts/Review-PR.Tests.ps1.github/scripts/RunTests.ps1.github/scripts/Set-ScreenResolution.Tests.ps1(deleted).github/scripts/shared/Detect-TestsInDiff.ps1.github/skills/verify-tests-fail-without-fix/scripts/verify-tests-fail.ps1eng/scripts/Set-ScreenResolution.ps1eng/scripts/update-cgmanifest.ps1
STEP 5b should consume these as honest partial results. They provide no evidence for or against the PR implementation and must not be treated as test failures or grounds to request changes.
🏁 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Winner
pr-plus-reviewer
The submitted runtime implementation is sound on code review, and pr-plus-reviewer preserves it unchanged while correcting the Apple sample's misleading UIDropProposal - Move label to AcceptedOperation - Move. It also has the strongest fresh platform evidence: all 41 filtered iOS gesture device tests passed. The focused unit-test command was blocked before test execution by unrelated existing RS0030 diagnostics, so that result is an environment/build limitation rather than a regression-test failure.
Because the winning candidate contains a change not present in the submitted PR, the required recommendation is REQUEST CHANGES.
Expert Review
- Verdict:
NEEDS_DISCUSSION - Confidence: low
- Inline findings: none (
inline-findings.jsonis[]) - Code assessment: the shared
Moveflag, multi-recognizer acceptance aggregation, Copy preference, explicit native proposal precedence, per-update state handling, andAllowsMoveOperationgate form a coherent implementation. - Evidence limitation: the trusted Gate is inconclusive and required-check coverage was not established as passing. This is not a failed fix.
- Non-blocking refinement: the Apple sample label described a native
UIDropProposaleven though the Move branch now uses sharedDragEventArgs.AcceptedOperation.
Candidate Comparison
| Rank | Candidate | Implementation | Validation | Assessment |
|---|---|---|---|---|
| 1 | pr-plus-reviewer |
Raw PR fix plus one sample-label correction; no runtime delta | iOS Gesture device tests: 41/41 passed. Focused unit command: build-blocked before tests by unrelated existing RS0030 diagnostics |
Best combination of implementation quality, sample accuracy, and fresh affected-platform evidence |
| 2 | pr |
Adds DataPackageOperation.Move; aggregates accepted operations on Apple platforms; prefers Copy; gates Move on session permission; preserves explicit native proposals |
Gate inconclusive. Pre-flight records focused unit tests passing, but the prior iOS run lacked a fresh result artifact | Runtime approach is sound and expert review found no blocking defect, but the sample label remains stale and platform evidence is weaker |
| 3 | try-fix-1 |
Planned a single authoritative effective acceptance instead of aggregating recognizer flags | Blocked before edits or tests; no diff | An unimplemented hypothesis with no regression evidence cannot outrank working candidates |
| 4 | try-fix-2 |
No runtime approach was designed or applied | Blocked before edits or tests; no diff | No implementation or behavioral evidence |
No candidate failed a regression test. The pr-plus-reviewer unit command failed to build unrelated unchanged tests and therefore is classified as blocked, not as a candidate regression failure; both try-fix candidates were likewise environment-blocked without executing tests.
Comparative Rationale
The raw PR and pr-plus-reviewer share the same runtime mechanism, so the expert review's positive assessment applies equally to both. Aggregating flags is better supported by the submitted tests and preserves acceptance when passive or multiple enabled recognizers participate; the unimplemented try-fix-1 single-effective-acceptance idea has no code or test result demonstrating that it would preserve those semantics.
pr-plus-reviewer wins narrowly because its one-line label correction makes the sample accurately describe the API exercised by its Move switch, while its fresh iOS run verifies the unchanged runtime behavior. The remaining uncertainty is validation coverage, not a known product defect: the Gate remains inconclusive, Mac Catalyst was not runtime-tested, and the required focused unit command did not reach test execution in the candidate sandbox.
Required Change
Apply pr-plus-reviewer/reviewer.patch, which changes only:
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSDragAndDropRequestFullSize.xaml
from UIDropProposal - Move to AcceptedOperation - Move.
🔗 Regression Cross-Reference
🔍 Regression Cross-Reference
⚠ Overlaps with prior bug-fix PRs — same files modified, but no exact line revert detected.
📱 UI Tests — Button,Label,Layout
Detected UI test categories: Button,Label,Layout
✅ Deep UI tests — 415 passed, 0 failed, 8 skipped across 3 categories on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Button |
105/106 (1 skipped) ✓ | — |
Label |
113/115 (2 skipped) ✓ | — |
Layout |
197/202 (5 skipped) ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
🧭 Next Steps — reviewer changes required
The reviewer-enhanced candidate identified changes that are not yet in the submitted PR.
Why: The submitted runtime implementation is sound, and pr-plus-reviewer preserves it while correcting the Apple sample's stale Move label. It also has the strongest fresh platform evidence with 41 of 41 filtered iOS gesture device tests passing; the focused unit command was blocked before test execution by unrelated existing build diagnostics.
Address the actionable findings in this review before merging.
This comment has been minimized.
This comment has been minimized.
Tests Failure Analysis
🧪 CI Analysis — click to expand📊 maui-pr
🧪 maui-pr-devicetests
🧪 maui-pr-uitests
🧭 Follow-up — actions and refreshNext action: Re-run the iOS CollectionView and MacCatalyst Core device work items; confirm the new drag/drop cases complete before attributing either device failure.
|

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 of Change
Adds
DataPackageOperation.Move = 2so a drop target can request Move through the sharedDragEventArgs.AcceptedOperationAPI.On iOS and Mac Catalyst, preserve and aggregate accepted operations rather than reducing them to a Boolean. Propose native Move only when the drag session permits it. Default Copy behavior, Copy preference for
Copy | Move, acceptance across multiple recognizers, and explicit native drop-proposal precedence are preserved.Windows and Android framework implementations are unchanged. The Windows sample explicitly opts its source into native
Copy | Movepermissions, and the Apple sample uses shared Move acceptance. Updates API declarations and documents the application-owned data changes.This does not automatically remove source data, reorder collections, or implement CollectionView reordering. Applications still own those changes. It also does not guarantee specific preview dimensions.
Release Target and Regression Risk
This should still be safe to consider for .NET 11: the behavior is opt-in, the implementation is narrow, and the existing supported
None/Copybehavior is preserved. Independent reviews with GPT-6 Astra and Claude Opus 4.8 found no concrete regression for those existing supported inputs, supported by the local results below.If this is too late in the .NET 11 release cycle, we can defer it to .NET 12. Preserving existing behavior takes priority over landing the feature before the cutoff. This is not an unconditional last-minute merge recommendation: normal candidate CI and affected-platform validation should still gate acceptance, particularly Mac Catalyst, which shares the changed Apple delegate, and the Windows sample's source-operation negotiation.
One compatibility caveat is explicit: on Apple platforms, previously undefined numeric enum values can behave differently. For example,
(DataPackageOperation)4previously fell back to Copy and now results in Cancel when no native proposal override is provided. This is outside the previously declaredNone/Copycontract, but is not a claim of identical behavior for every numeric cast.Validation
net11.0The existing UI tests exercise real gestures, cross-layout drops, event delivery, platform event arguments, and drag/drop coordinates. Additional local Sandbox/Appium checks covered eight scenarios, including default Copy, explicit Move, rejected drops, cancellation outside a target, native overrides, and requesting full-size previews.
Native regression coverage includes source Move restrictions;
None, Copy, Move, and combined flags; missing/disabled recognizers; recognizer ordering and passive recognizers; custom native proposals; per-update state reset; and disabling, removing, and replacing recognizers between updates.Validation limits: iOS ran on an iPhone 17 Pro simulator with iOS 26.4 using the worktree-local .NET 11 RC2 SDK and iOS workload. Local toolchain workarounds included an app-only runtime override,
MtouchLink=SdkOnly, andValidateXcodeVersion=false; those temporary project/harness changes are not included in this PR. Windows, Android, and Mac Catalyst have not been runtime-tested locally. A fail-without-fix comparison was not completed. Local results do not replace standard release-configuration or candidate CI validation.Issues Fixed
Fixes #16472