Skip to content

[WinUI][CV2] CollectionView2 Handler Implementation for Windows - #34600

Merged
PureWeen merged 119 commits into
net11.0from
BugFixes_WinUI_CV2
Jun 22, 2026
Merged

[WinUI][CV2] CollectionView2 Handler Implementation for Windows#34600
PureWeen merged 119 commits into
net11.0from
BugFixes_WinUI_CV2

Conversation

@SuthiYuvaraj

@SuthiYuvaraj SuthiYuvaraj commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Introduction

This PR implements the CollectionView2 (CV2) handler for Windows (WinUI), bringing the new ItemsRepeater-based CollectionView architecture to the Windows platform. This is part of the ongoing effort to replace the legacy ListView-based CollectionView implementation with a modern, performant, and feature-complete handler across all platforms.

The CV2 handler on Windows leverages WinUI's ItemsRepeater control as the virtualizing layout engine, providing better performance, smoother scrolling, and more consistent behavior aligned with the CV2 implementations on Android, iOS, and MacCatalyst.

Description of Changes

New Windows CV2 Handler Architecture

  • ItemsViewHandler2.Windows.cs — Core handler implementation mapping all CollectionViewproperties and commands to the WinUI ItemsRepeater-based view. Handles layout mapping (LinearItemsLayoutStackLayout, GridItemsLayoutUniformGridLayout), scroll management, selection, snapping, incremental loading, and RefreshView integration.

  • CollectionViewHandler2.Windows.cs — CollectionView-specific handler derived from the base items view handler, implementing selection modes (None, Single, Multiple), visual states, pre-selection, and pointer-based item interaction.

  • MauiItemsView.cs — Custom WinUI UserControl hosting the ItemsRepeater inside a ScrollViewer, with support for Header/Footer, EmptyView overlay, and RefreshContainer wrapping.

  • GroupableUniformGridLayout.cs — Custom layout that extends UniformGridLayout behavior to support grouped collection scenarios with proper group header/footer sizing.

Item Source & Templating Pipeline

  • ItemFactory.csIElementFactory implementation that creates WinUI elements from MAUI DataTemplate/DataTemplateSelector, manages recycling, and handles grouped vs flat item sources.

  • ObservableItemTemplateCollection2.cs — Bridges INotifyCollectionChanged source collections to ItemsRepeater-compatible observable collections, translating insert/remove/replace/move/reset operations.

  • GroupedItemTemplateCollection2.cs — Flattens grouped source data (with group headers, items, and group footers) into a single linear collection consumable by ItemsRepeater, tracking group boundary indices.

  • TemplatedItemSourceFactory2.cs — Factory that selects the appropriate templated collection type (observable, grouped, or enumerable context) based on the items source characteristics.

  • ItemTemplateContext2.cs, ItemTemplateContextEnumerable2.cs, ItemTemplateContextList2.cs — Context wrappers for item template binding.

Supporting Changes

  • ItemsViewExtensions.Windows.cs — New extension class with helper methods for converting MAUI layout types, snap point settings, and sizing strategies to their WinUI equivalents.

  • ItemsViewStyles.xaml — Updated WinUI resource dictionary with refined styles and templates for CV2 items, group headers/footers, header/footer, and empty view containers.

  • AppHostBuilderExtensions.cs — Registered the CV2 handler mappings for Windows in the MAUI host builder, gated behind the CollectionView2 runtime feature flag.

  • RuntimeFeature.cs — Added the CollectionView2 feature switch for conditional handler activation.

  • PublicAPI.Unshipped.txt — Added 43 new public API entries for the Windows CV2 surface area.

  • Build property integration — Updated .csproj files and build targets to include the UseCollectionView2 MSBuild property for opt-in activation.

Issues Fixed

The following issues are addressed by this implementation and the associated bug fixes:

Issue Description
#28895 CollectionView2 Implementation
#22320 IEnumerable source rendering not working in CollectionView
#26187 UITest failure — CollectionView items not displaying correctly
#27797 UITest failure — CollectionView interaction issues
#28212 CollectionView item layout/rendering bug
#31899 CollectionView Windows-specific rendering issue
#32543 CollectionView selection/interaction bug
#33487 CollectionView layout calculation issue
#34754 Drag and Drop and CanMixGroups support was not available

Major Functional Improvements

  • Layout: Fixed GridItemsLayout span width; fixed LayoutOptions alignment; fixed CornerRadius rendering; fixed item margin and pointer-over visuals.
  • Scrolling: Fixed PullToRefresh with ScrollViewer; fixed KeepScrollOffset/KeepItemsInView; fixed ScrollTo on unloaded view; fixed horizontal flicker.
  • Grouping: Fixed group header/footer rendering; fixed grouped grid layout; fixed ScrollTo for grouped items.
  • EmptyView: Fixed visibility toggling; removed unnecessary measure pass.
  • MeasureFirstItem: Fixed incorrect size with URL-based images; fixed size recalculation on DataTemplate change.
  • Data: Fixed DataTemplateSelector not updating on CollectionChanged.
  • Orientation: Fixed orientation switch not updating layout.

Platforms Affected

  • Windows (WinUI)

UI Difference from CV1

Selection UI
Selection appearance differs from CV1, where the selected item is now highlighted using a border that fully wraps the item, instead of the previous visual style.

Output Screenshot

CV1 Behavior CV2 Behavior
Before Fix After Fix
Before Fix - Multi Select After Fix - Multi Select

Drag and Drop Implementation

CV1 Behavior CV2 Behavior
CV1DragandDrop.mp4
AnimationFinal.mp4

Testing

  • Existing CollectionView UITests passing on Windows with CV2 handler enabled
  • Manual testing scenarios validated for: flat lists, grouped lists, grid layouts, selection modes, scrolling, snap points, pull-to-refresh, empty views, header/footer, incremental loading, and data template selectors

@SuthiYuvaraj

Copy link
Copy Markdown
Contributor Author

Hi @kubaflo , The conflict has been resolved. Please review and let me know if you have any feedback or concerns.

@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 22, 2026

@PureWeen PureWeen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Round 4 — Adversarial Multi-Model Review

Methodology: 3 independent reviewers (different model families) reviewed the changes since the previous round, with adversarial consensus — unanimous findings included directly, single-reviewer findings sent through a dispute round where the other two models weigh in. Factual claims were verified against source before posting.

Scope: the delta since the previous review HEAD — the ObservableItemTemplateCollection2 null-handling change, the CV1 ItemsViewHandler.Windows.cs update, MauiItemsView.DragDrop additions, CollectionViewHandler2 try/finally, ItemTemplateContext2, and the eng/pipelines UI-test YAML changes — plus the interactions those changes expose in sibling files.

✅ Verified correct (do not revert)

  • The null-handling change (removing if (item is null) continue; in ObservableItemTemplateCollection2) is correct and fixes a latent desync: Reset() already kept nulls while PopulateInitialItems/Add/Replace dropped them, so the wrapper could hold fewer entries than the source and drift index alignment — which MoveItemAndSyncSource relies on for drag/drop. 3/3 reviewers confirmed a null item renders safely (null BindingContext → blank cell, matching CV1; DataTemplateSelector.SelectTemplate(null, …) does not crash in framework code).
  • CollectionViewHandler2.UpdateItemsSource now resets _ignorePlatformSelectionChange in a finally. ✓
  • ItemFactory now assigns IsHeaderOrFooter unconditionally for new and recycled wrappers. ✓
  • CV1 ItemsViewHandler.Windows.cs disconnect-safety + deferred ScrollIntoView. ✓
  • MauiItemsView.DragDrop Loaded re-subscription is idempotent and unwired on disconnect. ✓
  • eng/pipelines UI-test YAML: every dependsOn resolves; the Mono→CoreCLR migration left no dangling stage references. ✓

Findings (each 3/3 consensus after the dispute round)

All three are downstream consequences of the (correct) decision to let null source items flow through — three different consumers don't yet handle the now-reachable null.

ItemFactory.cs (~L124) — null data items render as Selected. SelectionMode=Single + nothing selected + a null source item → object.Equals(null, null) == true highlights the blank cell. Fix: guard templateContext.Item is not null before comparing. (inline)

⚠️ MauiItemsView.DragDrop.cs (~L1266) — stale drag index on null cells. UpdateAllContainerIndices skips null-item containers, so their Tag goes stale after a reorder and dragging the blank cell moves the wrong row. 1 reviewer rated this ❌ (silent data corruption). Fix: fail safe by clearing the tag (or use GetElementIndex). (inline)

⚠️ GroupedItemTemplateCollection2.cs (~L324) — grouped Replace with null desyncs. The null-skip that was correctly removed from the observable class still exists in the grouped sibling's HandleGroupItemsReplace, leaving the old context in place and emitting a malformed Replace. Fix: mirror the null-parity fix. (inline)

Open items from prior reviews (still unresolved — not re-flagged here)

ObservableItemTemplateCollection2.cs:178 (_innerCollectionChange not in try/finally), ItemFactory.cs:233 (RecycleElement doesn't clear BindingContext/DataContext), ItemFactory.cs:420 (MeasureFirstItem cache pollution), ItemsViewHandler2.Windows.cs:362 (collection-typed items flattened when IsGrouped=false), and the duplicate Windows failed-artifact name in ui-tests-build-sample.yml. @kubaflo's CHANGES_REQUESTED review remains open.

This review evaluates code only; CI status is out of scope.


Round‑4 update — 2026‑06‑22 (head unchanged at 27171d2643)

A follow‑up 3‑model adversarial pass was run against the unchanged head. No new merge‑blocker surfaced.

  • All three findings above (ItemFactory.cs:124, MauiItemsView.DragDrop.cs:1266, GroupedItemTemplateCollection2.cs:324) and every "open item from prior reviews" listed above remain unresolved — the head is identical, so nothing has changed.
  • The previously‑noted ItemsViewHandler2.Windows.cs:362 flatten open item was independently re‑confirmed: in the non‑grouped branch, when IsGrouped=false but the ItemsSource items are themselves non‑string IEnumerable, the IsItemsSourceGrouped heuristic (L360) flattens the source — whereas CV1 (CreateCollectionViewSource) binds each inner collection as a single item. Real CV1 behavior difference; non‑crashing; uncommon shape (also reachable if a model type happens to implement IEnumerable). Fix: gate the else‑branch flatten on IsGrouped.

One net‑new (non‑blocking) observation:

  • 💡 ObservableItemTemplateCollection2.cs — indexless Replace/Move would throw. If a custom INotifyCollectionChanged source raises Replace (L420) or Move (L239/L247) with a -1 starting index, the flat handlers compute args.OldStartingIndex + indexthis[-1]ArgumentOutOfRangeException. This is pre‑existing parity, not a regression introduced here: the current default CV1 ObservableItemTemplateCollection (Platform/Windows/CollectionView) has line‑for‑line identical Replace/Move with the same gap, while Remove in both already guards < 0 with a Reset(). Trigger is rare (ObservableCollection<T> always supplies indices), and the grouped sibling already bounds‑guards these paths (ResetWithoutResubscribe()). Optional fix (ideally cross‑platform): mirror the Remove < 0 → Reset() guard in Replace/Move.

Consolidated into this Round‑4 review rather than opening a 5th. Code‑only; CI out of scope.

{
bool isSelected = selectableItemsView.SelectionMode != SelectionMode.None &&
(selectableItemsView.SelectionMode == SelectionMode.Single
? object.Equals(selectableItemsView.SelectedItem, templateContext.Item)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Regression — Null data items render in the Selected visual state.
Flagged by: 3/3 reviewers

With SelectionMode="Single" and nothing selected, SelectedItem is null. For a null source element templateContext.Item is also null, so object.Equals(null, null) returns true and the blank cell is pushed into Selected on every (re)bind — even though no selection exists. This path became reachable now that ObservableItemTemplateCollection2 lets null items render instead of skipping them. (The Multiple branch is safe: SelectedItems.Contains(null) is false.)

Fix: require a non-null item before comparing, e.g.
bool isSelected = templateContext.Item is not null && selectableItemsView.SelectionMode != SelectionMode.None && (...)

foreach (var container in FindAllContainers())
{
var item = GetContainerItem(container);
if (item is not null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

⚠️ Logic / Data Lossnull-item containers keep a stale drag index, so dragging a blank cell after a reorder moves the wrong row.
Flagged by: 3/3 reviewers (1 rated this ❌ silent data corruption)

UpdateAllContainerIndices skips containers whose item is null (GetContainerItem returns the null BindingContext), so their Tag is never refreshed after a reorder. ItemContainer_DragStarting (~L417) then takes the item is null && Tag is int index path and resolves _draggedItem from the stale index — silently dragging whatever item now occupies that old slot. Trigger: a reorderable CollectionView whose source contains null items → reorder → drag the blank cell.

The skip is understandable (a null item can't be resolved by value), but resolving to a plausible-but-wrong index is worse than failing safe. Fix: clear the tag for unresolved containers so the drag cancels — else { container.Tag = null; } — or assign the authoritative visual index via repeater.GetElementIndex(container).

{
oldItems.Add(Items[replaceIndex + i]);
var item = e.NewItems[i];
if (item is null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

⚠️ Logic / Regression — Grouped Replace with a null value desyncs the wrapper from the source; the null-parity fix applied to ObservableItemTemplateCollection2 was not mirrored in this sibling class.
Flagged by: 3/3 reviewers

When e.NewItems[i] is null, the continue skips both Items[replaceIndex + i] = newItem and newItems.Add(...), leaving the old context in Items while the source now holds null at that index — breaking the exact index-alignment invariant this PR establishes elsewhere. RebuildFlatList and HandleGroupItemsAdd already keep nulls, so this branch is inconsistent. It also emits a malformed Replace (NewItems.Count < OldItems.Count) to the live ItemsRepeater/ItemsSourceView.

(Verified: the 4-arg NotifyCollectionChangedEventArgs(Replace, …) constructor does not throw on unequal counts, so the symptom is desync + a contract-violating event, not an immediate exception.)

Trigger: a grouped CollectionView whose group is an IList/ObservableCollection and an element is replaced with null (group[i] = null).

Fix: keep null parity — drop the if (item is null) continue; and always assign + add a null-backed context, matching Add/Rebuild.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 3 findings

See inline comments for details.

{
oldItems.Add(Items[replaceIndex + i]);
var item = e.NewItems[i];
if (item is null)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[major] CollectionView Shared Models — Grouped item replacement drops null values. In a grouped ObservableCollection, replacing an item with null hits this continue, leaving the old ItemTemplateContext2 in Items while raising a Replace notification with mismatched old/new item lists. Concrete scenario: a grouped CollectionView whose group contains nullable items replaces group[0] with null; CV2 keeps rendering the old item instead of the expected blank/null cell.


foreach (var group in itemsSource)
{
if (group is IList groupList)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[major] CollectionView Windows — Grouped ScrollTo only handles groups that implement IList, but the grouped data source/display path accepts any non-string IEnumerable group. A CollectionView grouped with LINQ GroupBy/IGrouping will render, but ScrollTo(groupIndex, itemIndex) returns -1 because the target group is skipped here. Use enumerable counting/indexing fallback like GroupedItemTemplateCollection2 does instead of requiring IList.

if (PlatformView is null || ItemsView is null)
return;

var selectedItem = PlatformView.SelectedItem is ItemTemplateContext2 itemPair

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[major] CollectionView Windows Selection — Platform-to-MAUI selection unwraps every ItemTemplateContext2 without excluding group headers/footers. The header/footer template removes visual selection chrome but does not remove those contexts from the WinUI ItemsView selection model, so clicking/focusing a group header can set SelectedItem to the group object instead of ignoring the selection. Filter IsHeader/IsFooter here and in multiple-selection extraction before updating MAUI selection.

@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR labels Jun 22, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@SuthiYuvaraj — new AI review results are available based on this last commit: 0b642fa. To request a fresh review after new comments or commits, comment /review rerun.

Gate Inconclusive Confidence Low Platform Windows


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: WINDOWS · Base: net11.0 · Merge base: bed36265

🩺 Base branch does not compile — the without-fix build failed. The gate's "does the test fail without the fix" check is unreliable here; this usually means main is broken or a merge-base file went missing. Investigate before trusting this gate.

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ UITest UITest 🛠️ BUILD ERROR ❌ FAIL — 8742s
🔴 Without fix — 🖥️ UITest: 🛠️ BUILD ERROR · 237s

(truncated to last 15,000 chars)

\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(175,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapEmptyView(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(180,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapEmptyViewTemplate(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(185,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapFlowDirection(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(190,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapIsVisible(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(196,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapItemsLayout(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(201,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapHeader(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(206,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapHeaderTemplate(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(211,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapFooter(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(216,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.MapFooterTemplate(Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView!>! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(228,26): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.ConnectHandler(Microsoft.UI.Xaml.Controls.ItemsView! platformView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(221,32): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.CreatePlatformView() -> Microsoft.UI.Xaml.Controls.ItemsView!' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(248,26): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.DisconnectHandler(Microsoft.UI.Xaml.Controls.ItemsView! platformView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(419,25): error RS0016: Symbol 'virtual Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.UpdateItemsSource() -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\ItemsViewHandler2.Windows.cs(704,17): error RS0016: Symbol 'Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.UpdateItemsLayout() -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(14,9): error RS0016: Symbol 'Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.CollectionViewHandler2() -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(19,9): error RS0016: Symbol 'Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.CollectionViewHandler2(Microsoft.Maui.PropertyMapper? mapper = null) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(43,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapIsGrouped(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.GroupableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(55,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapGroupHeaderTemplate(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.GroupableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(60,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapGroupFooterTemplate(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.GroupableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(65,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapItemSizingStrategy(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.ItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(71,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapItemsSource(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.SelectableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(76,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapSelectedItem(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.SelectableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(81,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapSelectedItems(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.SelectableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(93,21): error RS0016: Symbol 'static Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.MapSelectionMode(Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2! handler, Microsoft.Maui.Controls.SelectableItemsView! itemsView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(157,26): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.ConnectHandler(Microsoft.UI.Xaml.Controls.ItemsView! platformView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(190,26): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.DisconnectHandler(Microsoft.UI.Xaml.Controls.ItemsView! platformView) -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(209,26): error RS0016: Symbol 'override Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2.UpdateItemsSource() -> void' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md) [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net11.0-windows10.0.19041.0]
    0 Warning(s)
    50 Error(s)

Time Elapsed 00:02:32.59

🟢 With fix — 🖥️ UITest: FAIL ❌ · 8742s

(truncated to last 15,000 chars)

MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("Default Text","VerticalGridCode",101,11) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("Default Text","HorizontalGridCode",101,11) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("DataTemplate","VerticalListCode",19,6) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("DataTemplate","HorizontalListCode",19,6) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("DataTemplate","VerticalGridCode",19,6) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed VisitAndUpdateItemsSource("DataTemplate","HorizontalGridCode",19,6) [4 m 15 s]
  Error Message:
   OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

>>>>> 6/22/2026 4:17:11 PM The SaveDeviceDiagnosticInfo threw an exception during VisitAndUpdateItemsSourceUITests(Windows).
Exception details: System.InvalidOperationException: Call InitialSetup before accessing the App property.
   at UITest.Appium.NUnit.UITestContextBase.get_App() in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 32
   at UITest.Appium.NUnit.UITestBase.SaveDeviceDiagnosticInfo(String note, Boolean storeForReattachment) in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 255
TearDown failed for test fixture Microsoft.Maui.TestCases.Tests.VisitAndUpdateItemsSourceUITests(Windows)
OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified
TearDown : System.InvalidOperationException : Call InitialSetup before accessing the App property.
StackTrace:    at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Appium.AppiumDriver..ctor(ICommandExecutor commandExecutor, ICapabilities appiumOptions)
   at UITest.Appium.AppiumWindowsApp..ctor(Uri remoteAddress, IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumWindowsApp.cs:line 11
   at UITest.Appium.AppiumServerContext.CreateUIClientContext(IConfig config) in /_/src/TestUtils/src/UITest.Appium/AppiumServerContext.cs:line 41
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context, Boolean reset) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 77
   at UITest.Appium.NUnit.UITestContextBase.InitialSetup(IServerContext context) in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 55
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 215
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
--TearDown
   at UITest.Appium.NUnit.UITestContextBase.get_App() in /_/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs:line 32
   at UITest.Appium.NUnit.UITestBase.OneTimeTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 244
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 11.0.0-preview.5.26256.105)
[xUnit.net 00:00:00.09]   Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.26]   Discovered:  Controls.TestCases.WinUI.Tests
Results File: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\UITest.trx

Total tests: 87
     Failed: 87
 Total time: 2.3471 Hours
Test Run Failed.
>>> TRX_RESULT_FILE: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\UITest.trx

⚠️ Failure Details

  • 🛠️ UITest without fix: build failed before tests could run
    • D:\a\1\s\src\Controls\src\Core\Handlers\Items2\CollectionViewHandler2.Windows.cs(12,22): error RS0016: Symbol 'Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2' is not part of the declar...
  • UITest FAILED with fix (should pass)
    • Clicked [4 m 11 s]; IsEnabled [4 m 11 s]; IsVisible [4 m 11 s]; IsEnabled [4 m 16 s]; IsVisible [4 m 16 s]; ItemsFromViewModelShouldBeSelected [4 m 16 s]; SelectionShouldUpdateBinding [4 m 15 s]; DragAndDropBetweenLayouts [4 m 16 s]; DragEventCoordinates [4 m 16 s]; DragEvents [4 m 16 s]; DragStartEventCoordinates [4 m 16 s]; PlatformDragEventArgs [4 m 16 s]; IsEnabled [4 m 16 s]; IsVisible [4 m 16 s]; DisabledSingleTap [4 m 15 s]; DoubleTap [4 m 15 s]; DynamicallyAddedTapGesturesDontCauseMultipleTapEvents [4 m 15 s]; PointerGestureTest [4 m 15 s]; SingleTap [4 m 15 s]; Aspect [4 m 16 s]; Aspect_AspectFill [4 m 16 s]; Aspect_AspectFit [4 m 16 s]; Aspect_Center [4 m 16 s]; Aspect_Fill [4 m 16 s]; BorderColor [4 m 16 s]; BorderColor_WithBackground [4 m 16 s]; BorderWidth [4 m 16 s]; BorderWidth_WithBackground [4 m 16 s]; Clicked [4 m 16 s]; Command [4 m 16 s]; CornerRadius [4 m 16 s]; CornerRadius_WithBackground [4 m 16 s]; IsEnabled [4 m 16 s]; IsVisible [4 m 16 s]; Padding [4 m 16 s]; Padding_Add [4 m 16 s]; IsAnimationPlaying [4 m 15 s]; IsEnabled [4 m 15 s]; IsVisible [4 m 15 s]; Source_FontImageSource [4 m 15 s]; Bugzilla28570Test [4 m 15 s]; Issue35127Test [4 m 16 s]; Bugzilla41415Test [4 m 16 s]; Bugzilla44461Test [4 m 16 s]; Bugzilla49069Test [4 m 15 s]; VerifyCheckBoxUnCheckedState [4 m 16 s]; VerifyCheckBoxCheckedState [4 m 16 s]; ClearingGroupedNoCrash [4 m 15 s]; NoBindingErrors [4 m 16 s]; DynamicallyLoadCollectionView [4 m 16 s]; CollectionViewItemsSourceTypesDisplayAndDontCrash [4 m 16 s]; KeepLastItemInView [4 m 15 s]; KeepScrollOffset [4 m 15 s]; AddingGroupToUnviewedGroupedCollectionViewShouldNotCrash [4 m 16 s]; AddingItemToUnviewedCollectionViewShouldNotCrash [4 m 16 s]; EmptyViewShouldNotCrash [4 m 16 s]; CollectionShouldInvalidateOnVisibilityChange [4 m 15 s]; MeasuringEmptyScrollViewDoesNotCrash [4 m 16 s]; ScrollViewNoContentTest [4 m 16 s]; ScrollViewObjectDisposedTest [4 m 15 s]; VerifySwipeViewApperance [4 m 16 s]; VerifyTimePickerAppearance [4 m 16 s]; FontFamily [4 m 16 s]; FontFamilyLoadsDynamically [4 m 16 s]; IsEnabled [4 m 16 s]; IsVisible [4 m 16 s]; SpanTapped [4 m 16 s]; IsEnabled [4 m 16 s]; IsVisible [4 m 16 s]; ScrollToElement1Start [4 m 16 s]; ScrollToElement2Center [4 m 16 s]; ScrollToElement3End [4 m 16 s]; ScrollToY [4 m 16 s]; ScrollToYTwice [4 m 16 s]; ScrollUpAndDownWithGestures [4 m 16 s]; DecreaseStepper [4 m 16 s]; IncreaseStepper [4 m 16 s]; VisitAndUpdateItemsSource("DataTemplate","VerticalListCode",19,6) [4 m 15 s]; VisitAndUpdateItemsSource("DataTemplate","HorizontalListCode",19,6) [4 m 15 s]; VisitAndUpdateItemsSource("DataTemplate","VerticalGridCode",19,6) [4 m 15 s]; VisitAndUpdateItemsSource("DataTemplate","HorizontalGridCode",19,6) [4 m 15 s]
    • OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the command. Original error: The system cannot find the file specified; OneTimeSetUp: OpenQA.Selenium.UnknownErrorException : An unknown server-side error occurred while processing the comman...
📁 Fix files reverted (11 files)
  • eng/cake/dotnet.cake
  • eng/devices/windows.cake
  • eng/pipelines/common/ui-tests-build-sample.yml
  • eng/pipelines/common/ui-tests-steps.yml
  • eng/pipelines/common/ui-tests.yml
  • src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets
  • src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs
  • src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs
  • src/Controls/src/Core/Platform/Windows/CollectionView/ItemsViewStyles.xaml
  • src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
  • src/Core/src/RuntimeFeature.cs

New files (not reverted):

  • src/Controls/src/Core/Handlers/Items/ItemsViewExtensions.Windows.cs
  • src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
  • src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
  • src/Controls/src/Core/Handlers/Items2/ReorderableItemsViewHandler2.Windows.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/GroupableUniformGridLayout.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContextEnumerable2.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContextList2.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/ObservableItemTemplateCollection2.cs
  • src/Controls/src/Core/Handlers/Items2/Windows/TemplatedItemSourceFactory2.cs

📱 UI Tests — CollectionView,DragAndDrop,Layout,ScrollView

Detected UI test categories: CollectionView,DragAndDrop,Layout,ScrollView


📋 Pre-Flight — Context & Validation

Issue: Not explicitly linked in fetched metadata - CollectionView2 Windows handler follow-up context
PR: #34600 - [WinUI][CV2] CollectionView2 Handler Implementation for Windows
Platforms Affected: Windows
Files Changed: 18 implementation, 79 test

Key Findings

  • PR implements and enables the WinUI CollectionView2 handler using ItemsRepeater/ItemsView infrastructure.
  • GitHub CLI is unauthenticated in this environment, so context was gathered from public REST/diff data and the local PR review branch.
  • Changed implementation areas include Windows Items2 handler, grouped flattening, drag/drop, selection, layout, templates, registration, and UI-test pipeline configuration.
  • Candidate exploration should focus on alternatives to the PR's current implementation for grouped ScrollTo, grouped null replace handling, duplicate drag/drop identity, realized item cleanup, and header/footer selection filtering.

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: low
Errors: 4 | Warnings: 1 | Suggestions: 0

Key code review findings:

  • ❌ ItemsViewHandler2.Windows.cs: grouped ScrollTo resolution only handles IList groups even though grouped rendering supports enumerable groups.
  • ❌ GroupedItemTemplateCollection2.cs: grouped replace with a null new item can leave stale flattened UI and mismatched replacement payloads.
  • ❌ MauiItemsView.DragDrop.cs: grouped drag/drop locates the source row by first equality match, so duplicate value-equal items can move the wrong source item.
  • ❌ ItemsViewHandler2.Windows.cs: disconnect cleanup misses realized visible item views.
  • ⚠️ CollectionViewHandler2.Windows.cs: group header/footer contexts can flow into MAUI selection synchronization.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34600 Adds default-on Windows CollectionView2 handler and associated grouping/selection/drag-drop/layout/test infrastructure. ⚠️ INCONCLUSIVE (Gate) 100 files Original PR; prior gate could not build/run and must not be rerun here.

🔬 Code Review — Deep Analysis

Code Review — PR #34600

Independent Assessment

What this changes: Adds a Windows CV2 CollectionView handler using WinUI ItemsView/ItemsRepeater, selection/drag-drop/grouping/layout infrastructure, feature switch registration, and extra Windows UI-test pipeline legs/snapshots.
Inferred motivation: Enable the new CollectionView2 architecture on Windows while preserving CV1 test coverage via explicit CV1 pipeline configuration.

Reconciliation with PR Narrative

Author claims: Implements WinUI CV2 handler, fixes layout/selection/grouping/scrolling/data-template behavior, enables Windows by default, and adds CV1/CV2 UI-test coverage.
Agreement/disagreement: The broad intent matches the code. However, several current-code paths still contradict the claimed grouped collection, null item, drag/drop, cleanup, and CI-readiness guarantees.

Prior Review Reconciliation

Prior ❌ Error Finding Source Status Evidence
Grouped ScrollTo only handles IList groups though rendering supports enumerable groups MauiBot ❌ Unresolved ItemsViewHandler2.Windows.cs:1785 and :1899 still skip groups not implementing IList.
Grouped replace with null new item leaves stale UI / mismatched replace payload MauiBot ❌ Unresolved GroupedItemTemplateCollection2.cs:324-325 still continues on null replacement.
Grouped drag/drop finds first equality match and can move wrong duplicate item MauiBot ❌ Unresolved MauiItemsView.DragDrop.cs:827 still uses `ReferenceEquals(...)
Earlier performance/observable-collection/null-item findings PureWeen / kubaflo ✅ Fixed / partially obsolete Current code has cache/try-cleanup/null-item changes; not all earlier exact line findings still apply.
Build Analysis / CI failures PureWeen ❌ Unresolved Public checks show Build Analysis, maui-pr, and maui-pr-uitests failures.

Blast Radius Assessment

  • Runs for all instances: yes — Windows CollectionView is enabled by default via RuntimeFeature.IsWindowsCollectionView2HandlerEnabledByDefault = true.
  • Startup impact: medium — handler registration changes app-wide Windows handler selection.
  • Static/shared state: yes — feature switch and WinUI style/resource changes affect broad Windows app behavior.

CI Status

  • Required-check result: gh pr checks --required unavailable: GitHub CLI is unauthenticated (gh auth login, exit 4).
  • Public check result: failing — public commit checks show Build Analysis failure, maui-pr failure, and maui-pr-uitests failure.
  • Classification: undetermined / not fully classifiable without authenticated gh and deeper AzDO access.
  • Action taken: confidence capped low.

Findings

❌ Error — Grouped ScrollTo silently fails for enumerable groups

src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs:1785 and :1899

The grouped rendering path accepts enumerable group sources, but grouped scroll-index resolution still requires IList.

❌ Error — Replacing a grouped item with null corrupts collection notifications

src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs:324

On replace, null new items are skipped. That leaves the old flattened item in place while newItems has fewer entries than oldItems.

❌ Error — Grouped drag/drop can move the wrong duplicate item

src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs:827

The source row is located by first equality match. For duplicate value-equal items, drag/drop may mutate the wrong item.

❌ Error — Handler disconnect does not clean realized item views

src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs:305

Disconnect only cleans the recycle pool and header/footer/empty views. Realized visible item wrappers are not enumerated/disconnected on teardown.

⚠️ Warning — Group headers/footers can sync into MAUI selection

src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs:312

Selection unwraps every ItemTemplateContext2.Item, including header/footer contexts.

Failure-Mode Probing

  • Group source is IGrouping<TKey,T>: rendering can work, but grouped ScrollTo skips it because it is not IList.
  • Replace grouped item with null: old item remains in flattened list while notification claims replacement with a shorter new list.
  • Duplicate values in grouped drag/drop: equality search selects first equal item, not necessarily dragged item.
  • Navigate away with realized cells: recycle-pool cleanup misses visible wrappers, risking retained logical children/handlers.

Verdict: NEEDS_CHANGES

Confidence: low
Summary: The PR is a broad default-on Windows handler replacement with unresolved prior ❌ findings and additional lifecycle/selection concerns. CI is also red/undetermined under the available unauthenticated tooling, so this is not ready to merge.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix Enumerate Renderable Groups During ScrollTo ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
2 try-fix Null Context Replace Pairing ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
3 try-fix Capture Group-Local Drag Source ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
4 try-fix Detach Realized ElementWrappers on Disconnect ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
5 try-fix Structural Selection Filtering ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
6 try-fix Grouped Entry Identity Keys ⚠️ BLOCKED src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
Targeted Windows UI test did not run; NETSDK1005 missing net10.0-windows10.0.19041.0 assets.
PR PR #34600 Default-on Windows CollectionView2 handler with ItemsRepeater/ItemsView infrastructure. ⚠️ INCONCLUSIVE (Gate) 100 files Original PR; prior gate could not build/run and was not rerun.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No NO NEW IDEAS
claude-opus-4.7 2 Yes Stable per-entry identity layer keyed by group reference, item index, and kind; run as candidate 6.
gpt-5.3-codex 2 Yes Structurally non-selectable group header/footer contexts; run as candidate 5.
gpt-5.5 2 No NO NEW IDEAS

Exhausted: Yes
Selected Fix: None — every alternative candidate was blocked before tests executed by the same missing Windows target-assets environment issue, so no candidate is demonstrably better than PR #34600's current fix.

Attempt Narratives

try-fix-1: Enumerate Renderable Groups During ScrollTo

Result: Blocked

Approach description:

Approach: Enumerate Renderable Groups During ScrollTo

Change grouped ScrollTo index resolution to treat any non-string IEnumerable group as renderable, matching GroupedItemTemplateCollection2 flattening. Use IList/ICollection fast paths when available, but fall back to enumerating a group only during explicit ScrollTo resolution.

Different from existing fix: The PR's current Windows Items2 grouped ScrollTo path resolves only IList groups. This candidate keeps the same handler location but changes the algorithm to mirror the flattened rendered source contract (IEnumerable groups), without touching drag/drop, cleanup, or grouped collection replacement logic.

Test results and analysis:

Analysis

Result: Blocked

What happened: The targeted Windows CollectionView HostApp command started, validated prerequisites, then failed during dotnet build before tests could run. The error was NETSDK1005: �rtifacts\obj\Controls.TestCases.HostApp\project.assets.json does not contain target
et10.0-windows10.0.19041.0.

Why it was blocked: The failure occurred before executing tests and does not identify a compile error in the candidate diff. Per invocation constraints, the Windows UI test environment could not build/run the provided command, so this attempt is recorded as Blocked rather than Pass.

Self-review: 0 findings — clean; no concrete violations found against logic/correctness, CollectionView grouped data correctness, Windows null safety, or hot-path allocation guidance for this explicit ScrollTo path.

Insights: Enumerating renderable groups in grouped ScrollTo aligns index resolution with GroupedItemTemplateCollection2 rendering, while preserving IList/ICollection fast paths for list-backed groups.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
index 8f0640c723..56058533de 100644
--- a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
@@ -1782,38 +1782,30 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 
 		foreach (var group in itemsSource)
 		{
-			if (group is IList groupList)
+			if (!TryGetRenderableGroupItems(group, out var groupItems))
 			{
-				if (currentGroupIndex == groupIndex)
-				{
-					// Found the target group
-					if (hasGroupHeader)
-					{
-						flatIndex++; // Skip group header
-					}
-
-					// Check if itemIndex is within bounds of this group
-					if (itemIndex < 0 || itemIndex >= groupList.Count)
-					{
-						return -1;
-					}
+				currentGroupIndex++;
+				continue;
+			}
 
-					// Return the calculated flat index
-					return flatIndex + itemIndex;
+			if (currentGroupIndex == groupIndex)
+			{
+				if (itemIndex < 0)
+				{
+					return -1;
 				}
 
-				// Count items in this group to move to next group
 				if (hasGroupHeader)
 				{
 					flatIndex++;
 				}
-				flatIndex += groupList.Count;
-				if (hasGroupFooter)
-				{
-					flatIndex++;
-				}
+
+				return TryGetGroupItemOffset(groupItems, itemIndex, out var itemOffset)
+					? flatIndex + itemOffset
+					: -1;
 			}
 
+			flatIndex += GetFlatGroupLength(groupItems, hasGroupHeader, hasGroupFooter);
 			currentGroupIndex++;
 		}
 
@@ -1821,6 +1813,130 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 		return -1;
 	}
 
+	static bool TryGetRenderableGroupItems(object? group, out IEnumerable groupItems)
+	{
+		if (group is not string && group is IEnumerable items)
+		{
+			groupItems = items;
+			return true;
+		}
+
+		groupItems = Array.Empty<object>();
+		return false;
+	}
+
+	static int GetFlatGroupLength(IEnumerable groupItems, bool hasGroupHeader, bool hasGroupFooter)
+	{
+		int length = 0;
+		if (hasGroupHeader)
+		{
+			length++;
+		}
+
+		length += GetGroupItemCount(groupItems);
+
+		if (hasGroupFooter)
+		{
+			length++;
+		}
+
+		return length;
+	}
+
+	static int GetGroupItemCount(IEnumerable groupItems)
+	{
+		if (groupItems is ICollection collection)
+		{
+			return collection.Count;
+		}
+
+		int count = 0;
+		foreach (var unused in groupItems)
+		{
+			count++;
+		}
+
+		return count;
+	}
+
+	static bool HasAnyGroupItems(IEnumerable groupItems)
+	{
+		if (groupItems is ICollection collection)
+		{
+			return collection.Count > 0;
+		}
+
+		foreach (var unused in groupItems)
+		{
+			return true;
+		}
+
+		return false;
+	}
+
+	static bool TryGetGroupItemOffset(IEnumerable groupItems, int itemIndex, out int itemOffset)
+	{
+		if (groupItems is IList list)
+		{
+			if (itemIndex < list.Count)
+			{
+				itemOffset = itemIndex;
+				return true;
+			}
+
+			itemOffset = -1;
+			return false;
+		}
+
+		int index = 0;
+		foreach (var unused in groupItems)
+		{
+			if (index == itemIndex)
+			{
+				itemOffset = index;
+				return true;
+			}
+
+			index++;
+		}
+
+		itemOffset = -1;
+		return false;
+	}
+
+	static bool TryFindItemOffsetInGroup(IEnumerable groupItems, object item, out int itemOffset)
+	{
+		if (groupItems is IList list)
+		{
+			for (int i = 0; i < list.Count; i++)
+			{
+				if (Equals(list[i], item))
+				{
+					itemOffset = i;
+					return true;
+				}
+			}
+
+			itemOffset = -1;
+			return false;
+		}
+
+		int index = 0;
+		foreach (var groupItem in groupItems)
+		{
+			if (Equals(groupItem, item))
+			{
+				itemOffset = index;
+				return true;
+			}
+
+			index++;
+		}
+
+		itemOffset = -1;
+		return false;
+	}
+
 	/// <summary>
 	/// Finds the index of an item in the collection view by searching through the flattened list.
 	/// Used for non-grouped ScrollToMode.Element requests.
@@ -1889,74 +2005,34 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 		var hasGroupHeader = groupableItemsView.GroupHeaderTemplate is not null;
 		var hasGroupFooter = groupableItemsView.GroupFooterTemplate is not null;
 
-		// Find the target group and its items by matching the group object
-		IList? targetGroupItems = null;
-		int flatIndexOfGroup = 0;
 		int currentFlatIndex = 0;
 
 		foreach (var g in itemsSource)
 		{
-			if (g is not IList groupList)
+			if (!TryGetRenderableGroupItems(g, out var groupItems))
 			{
 				continue;
 			}
 
 			if (Equals(g, group))
 			{
-				targetGroupItems = groupList;
-				flatIndexOfGroup = currentFlatIndex;
-				break;
-			}
-
-			// Advance past this group's entries in the flat list
-			if (hasGroupHeader)
-			{
-				currentFlatIndex++;
-			}
-
-			currentFlatIndex += groupList.Count;
-
-			if (hasGroupFooter)
-			{
-				currentFlatIndex++;
-			}
-		}
-
-		if (targetGroupItems is null)
-		{
-			return -1;
-		}
+				if (item is null)
+				{
+					if (hasGroupHeader)
+					{
+						return currentFlatIndex;
+					}
 
-		// If item is null, scroll to the group header (if it exists)
-		if (item is null)
-		{
-			if (hasGroupHeader)
-			{
-				return flatIndexOfGroup;
-			}
+					return HasAnyGroupItems(groupItems) ? currentFlatIndex : -1;
+				}
 
-			// No header template — scroll to the first item in the group instead
-			if (targetGroupItems.Count > 0)
-			{
-				return flatIndexOfGroup;
+				int itemStartIndex = hasGroupHeader ? currentFlatIndex + 1 : currentFlatIndex;
+				return TryFindItemOffsetInGroup(groupItems, item, out var itemOffset)
+					? itemStartIndex + itemOffset
+					: -1;
 			}
 
-			return -1;
-		}
-
-		// Find the item within the target group
-		int itemStartIndex = flatIndexOfGroup;
-		if (hasGroupHeader)
-		{
-			itemStartIndex++;
-		}
-
-		for (int i = 0; i < targetGroupItems.Count; i++)
-		{
-			if (Equals(targetGroupItems[i], item))
-			{
-				return itemStartIndex + i;
-			}
+			currentFlatIndex += GetFlatGroupLength(groupItems, hasGroupHeader, hasGroupFooter);
 		}
 
 		return -1;

try-fix-2: Null Context Replace Pairing

Result: Blocked

Approach description:

Approach: Null Context Replace Pairing

Update grouped item replacement so a null replacement value is represented as a valid ItemTemplateContext2 whose Item is null, instead of skipping it. The replace path will require equal old/new range counts, update every flattened slot in the range, and emit a Replace notification with old and new payload lists of identical length.

Different from existing fix: PR #34600's current replace code skips null new items, producing mismatched notification payloads and stale flattened entries. This candidate treats null as data and preserves one old/new context pair per replaced index. It is also different from candidate 1, which focused on grouped ScrollTo resolution.

Test results and analysis:

Analysis

Result: Blocked

What happened: The targeted Windows UI test command started the HostApp build but failed before tests ran with NETSDK1005: project.assets.json does not have a target for
et10.0-windows10.0.19041.0.

Why it was blocked: This matches the prior environment/build setup blocker in the prompt. The candidate code was not exercised, so this attempt cannot be classified as Pass or logic Fail.

Self-review: 0 findings — clean; no findings recorded.

Insights: Treating null as a valid MAUI data item keeps grouped Replace payloads range-scoped and count-consistent: every old flattened context is replaced with exactly one new context, including a context whose Item is null.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs b/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
index 1a28430592..76c0794eef 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
@@ -48,7 +48,7 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		}
 	}
 
-	ItemTemplateContext2 CreateItemContext(object item) =>
+	ItemTemplateContext2 CreateItemContext(object? item) =>
 		new(_itemTemplate, item, _container, mauiContext: _mauiContext);
 
 	ItemTemplateContext2? CreateHeaderContext(object group) =>
@@ -307,24 +307,29 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		if (e.NewItems is null || e.OldItems is null)
 			return;
 
-		int replaceIndex = flatIndex + (e.NewStartingIndex >= 0 ? e.NewStartingIndex : 0);
-		if (replaceIndex < 0 || replaceIndex + e.NewItems.Count - 1 >= Items.Count)
+		int replaceCount = e.NewItems.Count;
+		if (replaceCount != e.OldItems.Count)
+		{
+			ResetWithoutResubscribe();
+			return;
+		}
+
+		int replaceIndex = flatIndex + (e.NewStartingIndex >= 0 ? e.NewStartingIndex : e.OldStartingIndex >= 0 ? e.OldStartingIndex : 0);
+		if (replaceIndex < 0 || replaceIndex + replaceCount > Items.Count)
 		{
 			ResetWithoutResubscribe();
 			return;
 		}
-		var oldItems = new List<ItemTemplateContext2>(e.NewItems.Count);
-		var newItems = new List<ItemTemplateContext2>(e.NewItems.Count);
+
+		var oldItems = new List<ItemTemplateContext2>(replaceCount);
+		var newItems = new List<ItemTemplateContext2>(replaceCount);
 
 		_suppressNotifications = true;
-		for (int i = 0; i < e.NewItems.Count; i++)
+		for (int i = 0; i < replaceCount; i++)
 		{
 			oldItems.Add(Items[replaceIndex + i]);
-			var item = e.NewItems[i];
-			if (item is null)
-				continue;
 
-			var newItem = CreateItemContext(e.NewItems[i]!);
+			var newItem = CreateItemContext(e.NewItems[i]);
 			newItems.Add(newItem);
 			Items[replaceIndex + i] = newItem;
 		}

try-fix-3: Capture Group-Local Drag Source

Result: Blocked

Approach description:

Approach: Capture Group-Local Drag Source

Capture the authoritative ItemsRepeater flat index at DragStarting, immediately map it to the mutable source group and group-local item index, and use that stored group/index during grouped drop instead of rediscovering the source row by ReferenceEquals/Equals search.

This preserves the dragged row for value-equal duplicates because the grouped move is anchored to the visual container index from drag start, not the first equal item in the group.

Different from existing fix: PR #34600's current code stores only _draggedSourceIndex and PerformGroupedReorder still searches groups for the first ReferenceEquals/Equals match. Candidate 3 stores the source group reference and group-local index at drag start and makes grouped reorder use that captured position.

Test results and analysis:

Analysis

Result: Blocked

What happened: The candidate was implemented and the required Windows DragAndDrop test command was run. The HostApp build failed before tests executed with NETSDK1005: project.assets.json does not have a target for net10.0-windows10.0.19041.0.

Why it blocked: This matches the known Windows UI test environment target-assets blocker from prior candidates, so the fix logic could not be validated empirically in this environment.

Self-review: 0 findings — clean; no critical/major issues found against the final diff.

Insights: Capturing the source group and group-local item index at DragStarting avoids grouped source rediscovery by first equality match and should preserve the dragged duplicate row when tests can run.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs b/src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs
index 469ec2e175..4e4edf1c75 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/MauiItemsView.DragDrop.cs
@@ -28,6 +28,9 @@ internal partial class MauiItemsView
 	// Used by PerformReorder to disambiguate value-equal duplicates (record structs,
 	// boxed primitives, repeated entries) where IndexOfItem would return the first match.
 	int _draggedSourceIndex = -1;
+	IList? _draggedSourceGroup;
+	int _draggedSourceGroupIndex = -1;
+	int _draggedSourceItemIndex = -1;
 	ItemContainer? _sourceContainer;
 	int _insertionIndex = -1;
 	bool _insertAfter;
@@ -430,7 +433,8 @@ internal partial class MauiItemsView
 		}
 
 		_draggedItem = item;
-		_draggedSourceIndex = GetContainerIndex(itemContainer);
+		_draggedSourceIndex = GetRepeaterElementIndex(itemContainer);
+		CaptureGroupedDragSource(_draggedSourceIndex);
 		_sourceContainer = itemContainer;
 
 		args.Data.Properties.Add("DragSource", "MauiItemsView");
@@ -807,42 +811,20 @@ internal partial class MauiItemsView
 		bool hasHeaders = groupableView.GroupHeaderTemplate is not null;
 		bool hasFooters = groupableView.GroupFooterTemplate is not null;
 
-		// Find which group the dragged item belongs to.
-		// Groups may be IEnumerable-only (e.g., IGrouping<K,V>), so enumerate rather
-		// than requiring IList for the search. IList is still required for mutation.
-		int sourceGroupIndex = -1;
-		int sourceItemIndex = -1;
-		IList? sourceGroup = null;
+		int sourceGroupIndex = _draggedSourceGroupIndex;
+		int sourceItemIndex = _draggedSourceItemIndex;
+		IList? sourceGroup = _draggedSourceGroup;
 
-		for (int g = 0; g < groupsList.Count; g++)
+		if (sourceGroupIndex < 0 ||
+			sourceItemIndex < 0 ||
+			sourceGroup is null ||
+			sourceItemIndex >= sourceGroup.Count)
 		{
-			if (groupsList[g] is not IEnumerable groupItems)
-			{
-				continue;
-			}
-
-			int i = 0;
-			foreach (var groupItem in groupItems)
-			{
-				if (ReferenceEquals(groupItem, _draggedItem) || Equals(groupItem, _draggedItem))
-				{
-					sourceGroupIndex = g;
-					sourceItemIndex = i;
-					sourceGroup = groupsList[g] as IList;
-					break;
-				}
-
-				i++;
-			}
-
-			if (sourceGroupIndex >= 0)
-			{
-				break;
-			}
+			return false;
 		}
 
-		// sourceGroup being null means the group is not mutable — reorder not possible.
-		if (sourceGroupIndex < 0 || sourceItemIndex < 0 || sourceGroup is null)
+		var sourceItem = sourceGroup[sourceItemIndex];
+		if (!ReferenceEquals(sourceItem, _draggedItem) && !Equals(sourceItem, _draggedItem))
 		{
 			return false;
 		}
@@ -860,10 +842,7 @@ internal partial class MauiItemsView
 				continue;
 			}
 
-			// Use ICollection.Count when available (O(1)); otherwise enumerate (O(n)).
-			int groupItemCount = groupsList[g] is ICollection coll
-				? coll.Count
-				: groupItems.Cast<object>().Count();
+			int groupItemCount = GetEnumerableCount(groupsList[g], groupItems);
 
 			int groupStart = flatPos;
 
@@ -904,9 +883,7 @@ internal partial class MauiItemsView
 			{
 				if (groupsList[g] is IEnumerable groupItems)
 				{
-					int groupItemCount = groupsList[g] is ICollection coll
-						? coll.Count
-						: groupItems.Cast<object>().Count();
+					int groupItemCount = GetEnumerableCount(groupsList[g], groupItems);
 
 					targetGroupIndex = g;
 					targetItemIndex = groupItemCount;
@@ -1107,6 +1084,100 @@ internal partial class MauiItemsView
 		return FindAllContainers().FirstOrDefault(c => GetContainerIndex(c) == index);
 	}
 
+	int GetRepeaterElementIndex(ItemContainer itemContainer)
+	{
+		var repeater = ItemsRepeaterControl;
+		if (repeater is not null)
+		{
+			int repeaterIndex = repeater.GetElementIndex(itemContainer);
+			if (repeaterIndex >= 0)
+			{
+				return repeaterIndex;
+			}
+		}
+
+		if (itemContainer.Tag is int tagIndex)
+		{
+			return tagIndex;
+		}
+
+		return -1;
+	}
+
+	void CaptureGroupedDragSource(int flatIndex)
+	{
+		_draggedSourceGroup = null;
+		_draggedSourceGroupIndex = -1;
+		_draggedSourceItemIndex = -1;
+
+		if (flatIndex < 0 ||
+			_mauiVirtualView is not GroupableItemsView { IsGrouped: true } groupableView ||
+			_mauiVirtualView.ItemsSource is not IList groupsList)
+		{
+			return;
+		}
+
+		bool hasHeaders = groupableView.GroupHeaderTemplate is not null;
+		bool hasFooters = groupableView.GroupFooterTemplate is not null;
+		int flatPos = 0;
+
+		for (int g = 0; g < groupsList.Count; g++)
+		{
+			object? group = groupsList[g];
+			if (group is not IEnumerable groupItems)
+			{
+				continue;
+			}
+
+			if (hasHeaders)
+			{
+				if (flatIndex == flatPos)
+				{
+					return;
+				}
+
+				flatPos++;
+			}
+
+			int groupItemCount = GetEnumerableCount(group, groupItems);
+			if (flatIndex >= flatPos && flatIndex < flatPos + groupItemCount)
+			{
+				_draggedSourceGroup = group as IList;
+				_draggedSourceGroupIndex = g;
+				_draggedSourceItemIndex = flatIndex - flatPos;
+				return;
+			}
+
+			flatPos += groupItemCount;
+
+			if (hasFooters)
+			{
+				if (flatIndex == flatPos)
+				{
+					return;
+				}
+
+				flatPos++;
+			}
+		}
+	}
+
+	static int GetEnumerableCount(object? source, IEnumerable enumerable)
+	{
+		if (source is ICollection collection)
+		{
+			return collection.Count;
+		}
+
+		int count = 0;
+		foreach (var _ in enumerable)
+		{
+			count++;
+		}
+
+		return count;
+	}
+
 	/// <summary>
 	/// Finds the realized container whose binding context equals <paramref name="targetItem"/>
 	/// by identity. Unlike <see cref="FindContainerByIndex"/>, this is safe to call from
@@ -1306,6 +1377,9 @@ internal partial class MauiItemsView
 
 		_draggedItem = null;
 		_draggedSourceIndex = -1;
+		_draggedSourceGroup = null;
+		_draggedSourceGroupIndex = -1;
+		_draggedSourceItemIndex = -1;
 		_insertionIndex = -1;
 		_insertAfter = false;
 		StopAutoScroll();

try-fix-4: Detach Realized ElementWrappers on Disconnect

Result: Blocked

Approach description:

Approach: Detach Realized ElementWrappers on Disconnect

Add a full-teardown path to the Windows CV2 item factory that walks the currently realized WinUI ItemContainer tree during handler disconnect and detaches each ElementWrapper's MAUI view: unwire lifecycle observers, disconnect handlers, clear binding/data contexts, remove the logical child, clear wrapper content, and sever the ItemContainer child reference.

Different from existing fix: PR #34600's current disconnect path cleans collection subscriptions, the recycle pool, and header/footer/empty views, but avoids CleanUpCollectionViewSource() and therefore does not explicitly detach realized visible item wrappers. This candidate keeps that avoidance of CollectionViewSource.Source mutation, but adds a separate idempotent realized-element teardown path focused only on lifecycle cleanup.

Test results and analysis:

Analysis

Result: Blocked

What happened: The targeted Windows CollectionView host-app test command started successfully but the build failed before tests ran.

Why it was blocked: The environment hit the same known NETSDK1005 blocker as prior candidates: project.assets.json does not contain the
et10.0-windows10.0.19041.0 target for Controls.TestCases.HostApp.csproj. Because the test environment cannot build the requested Windows UI test target, this candidate could not be empirically validated.

Self-review: 0 findings — clean, no findings.

Insights: The candidate isolates realized visible item cleanup from CollectionViewSource teardown by walking realized ItemContainer wrappers and severing MAUI logical child, handler, data context, content, and platform child references during DisconnectHandler.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
index 8f0640c723..4cbab0abfa 100644
--- a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
@@ -302,6 +302,7 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 
 		}
 
+		_itemFactory?.CleanUpRealizedElements(platformView);
 		_itemFactory?.CleanUp();
 		_itemFactory = null;
 
diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs b/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
index 97408f2374..836316defe 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
@@ -244,23 +244,41 @@ internal partial class ItemFactory(ItemsView view) : IElementFactory
 		{
 			foreach (var container in kvp.Value)
 			{
-				var wrapper = container?.Child as ElementWrapper;
-				var wrapperView = wrapper?.VirtualView as View;
-				if (wrapperView is not null)
-				{
-					wrapperView.BindingContext = null;
-					_view.RemoveLogicalChild(wrapperView);
-				}
-
-				if (wrapper is not null)
-				{
-					wrapper.DataContext = null;
-				}
+				CleanUpContainer(container);
 			}
 		}
 
 		_recyclePool.Clear();
 	}
+
+	/// <summary>
+	/// Detaches realized item containers still present in the platform visual tree.
+	/// </summary>
+	internal void CleanUpRealizedElements(Microsoft.UI.Xaml.Controls.ItemsView platformView)
+	{
+		var realizedContainers = new List<ItemContainer>();
+		foreach (var container in platformView.GetChildren<ItemContainer>())
+		{
+			if (container is not null)
+			{
+				realizedContainers.Add(container);
+			}
+		}
+
+		for (int i = 0; i < realizedContainers.Count; i++)
+		{
+			CleanUpContainer(realizedContainers[i]);
+		}
+	}
+
+	void CleanUpContainer(ItemContainer? container)
+	{
+		if (container?.Child is ElementWrapper wrapper)
+		{
+			wrapper.CleanUpVirtualView(_view);
+			container.Child = null;
+		}
+	}
 }
 
 /// <summary>
@@ -294,6 +312,27 @@ internal partial class ElementWrapper : ContentControl
 		}
 	}
 
+	/// <summary>
+	/// Fully detaches the hosted MAUI view during handler teardown.
+	/// </summary>
+	internal void CleanUpVirtualView(ItemsView itemsView)
+	{
+		Loaded -= OnLoadedCreatePlatformView;
+		UnwireContentSizeObserver();
+
+		if (VirtualView is View mauiView)
+		{
+			mauiView.BindingContext = null;
+			mauiView.DisconnectHandlers();
+			itemsView.RemoveLogicalChild(mauiView);
+		}
+
+		Content = null;
+		DataContext = null;
+		VirtualView = null;
+		IsHeaderOrFooter = false;
+	}
+
 	public ElementWrapper(IMauiContext context)
 	{
 		_context = context;

try-fix-5: Structural Selection Filtering

Result: Blocked

Approach description:

Approach: Structural Selection Filtering

Make ItemTemplateContext2 expose an explicit IsSelectable role and route every Windows Items2 selection synchronization path through that role. Header/footer contexts remain renderable with their existing templates and binding contexts, but they are ignored when platform selection flows back to MAUI and skipped when MAUI selection is projected to WinUI indices.

Different from existing fix: PR #34600 already carries header/footer metadata for display and container styling. This candidate uses that metadata at the selection boundary instead of changing ScrollTo, null replacement, drag/drop source identity, or disconnect cleanup. It structurally filters selection synchronization without treating null item values as header/footer.

Test results and analysis:

Analysis

Result: Blocked

What happened: The targeted Windows CollectionView host-app command started but failed during build before tests ran. The build reported NETSDK1005 because �rtifacts\obj\Controls.TestCases.HostApp\project.assets.json does not contain the
et10.0-windows10.0.19041.0 target.

Why it was blocked: This is the same missing-assets condition reported for prior candidates, so candidate behavior could not be empirically validated in this environment.

Self-review: 0 findings — clean; no critical/major issues found in the final diff.

Insights: The structural selection filter remains a viable candidate to test once the Windows HostApp restore/build assets include the required target framework.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
index 8e4b49e2df..f28144d5a8 100644
--- a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
@@ -309,9 +309,11 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 		if (PlatformView is null || ItemsView is null)
 			return;
 
-		var selectedItem = PlatformView.SelectedItem is ItemTemplateContext2 itemPair
-			? itemPair.Item
-			: PlatformView.SelectedItem;
+		if (!TryGetSelectableItem(PlatformView.SelectedItem, out var selectedItem))
+		{
+			UpdatePlatformSelection();
+			return;
+		}
 
 		ItemsView.SelectionChanged -= VirtualSelectionChanged;
 		ItemsView.SelectedItem = selectedItem;
@@ -393,9 +395,10 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 		var result = new HashSet<object>();
 		foreach (var item in PlatformView.SelectedItems)
 		{
-			var selectedItem = item is ItemTemplateContext2 itc ? itc.Item : item;
-			if (selectedItem is not null)
-				result.Add(selectedItem);
+			if (TryGetSelectableItem(item, out var selectedItem))
+			{
+				result.Add(selectedItem!);
+			}
 		}
 		return result;
 	}
@@ -452,11 +455,7 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 				int index = 0;
 				foreach (var nativeItem in itemList)
 				{
-					if (nativeItem is ItemTemplateContext2 itemPair && ItemsView.SelectedItems.Contains(itemPair.Item))
-					{
-						PlatformView.Select(index);
-					}
-					else if (ItemsView.SelectedItems.Contains(nativeItem))
+					if (TryGetSelectableItem(nativeItem, out var item) && ItemsView.SelectedItems.Contains(item))
 					{
 						PlatformView.Select(index);
 					}
@@ -482,8 +481,7 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 		int index = 0;
 		foreach (var nativeItem in itemList)
 		{
-			var actualItem = nativeItem is ItemTemplateContext2 itc ? itc.Item : nativeItem;
-			if (object.Equals(actualItem, targetItem))
+			if (TryGetSelectableItem(nativeItem, out var actualItem) && object.Equals(actualItem, targetItem))
 			{
 				return index;
 			}
@@ -491,6 +489,18 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 		}
 		return -1;
 	}
+
+	static bool TryGetSelectableItem(object? nativeItem, out object? item)
+	{
+		if (nativeItem is ItemTemplateContext2 context)
+		{
+			item = context.Item;
+			return context.IsSelectable;
+		}
+
+		item = nativeItem;
+		return true;
+	}
 }
 
 /// <summary>
diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs b/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
index 97408f2374..58ad8ff85c 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/ItemFactory.cs
@@ -119,7 +119,8 @@ internal partial class ItemFactory(ItemsView view) : IElementFactory
 				if (view is VisualElement visualElement &&
 					_view is SelectableItemsView selectableItemsView)
 				{
-					bool isSelected = selectableItemsView.SelectionMode != SelectionMode.None &&
+					bool isSelected = templateContext.IsSelectable &&
+						selectableItemsView.SelectionMode != SelectionMode.None &&
 						(selectableItemsView.SelectionMode == SelectionMode.Single
 							? object.Equals(selectableItemsView.SelectedItem, templateContext.Item)
 							: selectableItemsView.SelectedItems.Contains(templateContext.Item));
diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs b/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
index cd2c2837ca..07fafa2d26 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
@@ -37,6 +37,9 @@ internal class ItemTemplateContext2
 	/// <summary>Whether this context represents a group footer.</summary>
 	public bool IsFooter { get; }
 
+	/// <summary>Whether this context represents a selectable data item.</summary>
+	public bool IsSelectable => !IsHeader && !IsFooter;
+
 	public ItemTemplateContext2(DataTemplate mauiDataTemplate, object? item, BindableObject container,
 		double? height = null, double? width = null, Thickness? itemSpacing = null,
 		bool isHeader = false, bool isFooter = false, IMauiContext? mauiContext = null)

try-fix-6: Grouped Entry Identity Keys

Result: Blocked

Approach description:

Approach: Grouped Entry Identity Keys

Add a small grouped-entry identity layer to ItemTemplateContext2 and GroupedItemTemplateCollection2: each flattened grouped entry carries its group reference, item index, and structural kind (item/header/footer). Grouped collection changes update those identity fields, and grouped ScrollTo resolves against the flattened entry contexts instead of re-walking the raw source with Equals.

This is intentionally surgical: it does not refactor the handler pipeline or selection model. It preserves null data items as valid item contexts and keeps header/footer identity structural.

Different from existing fix: PR #34600's current code and candidates 1-5 patch individual raw-equality paths (enumerable ScrollTo, null replacement, drag source capture, disconnect cleanup, header/footer filtering). This candidate introduces explicit per-entry grouped identity metadata and routes grouped ScrollTo through that metadata rather than raw group/item equality.

Test results and analysis:

Analysis

Result: Blocked

What happened: The candidate was implemented and the required Windows CollectionView test command was run. The HostApp build stopped before compiling the changed handler code with NETSDK1005: project.assets.json does not contain
et10.0-windows10.0.19041.0 for Controls.TestCases.HostApp.

Why it was blocked: This matches the prior attempts' environment/setup blocker. The test command could not build/run the Windows UI test host, so this candidate could not be empirically validated.

Self-review: 0 findings — clean; no critical/major issues found in the final diff during inline review.

Insights: The identity-key abstraction can be kept localized to grouped ItemTemplateContext2 entries and GroupedItemTemplateCollection2, but fully covering drag and selection duplicates would require additional source-context plumbing and may be too broad for a single surgical attempt.

Diff:

diff --git a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
index 8e4b49e2df..a8db913e35 100644
--- a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.Windows.cs
@@ -310,7 +310,7 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 			return;
 
 		var selectedItem = PlatformView.SelectedItem is ItemTemplateContext2 itemPair
-			? itemPair.Item
+			? itemPair.EntryKind == ItemTemplateContextKind2.Item ? itemPair.Item : null
 			: PlatformView.SelectedItem;
 
 		ItemsView.SelectionChanged -= VirtualSelectionChanged;
@@ -393,9 +393,17 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 		var result = new HashSet<object>();
 		foreach (var item in PlatformView.SelectedItems)
 		{
-			var selectedItem = item is ItemTemplateContext2 itc ? itc.Item : item;
-			if (selectedItem is not null)
-				result.Add(selectedItem);
+			if (item is ItemTemplateContext2 itc)
+			{
+				if (itc.EntryKind == ItemTemplateContextKind2.Item && itc.Item is not null)
+				{
+					result.Add(itc.Item);
+				}
+			}
+			else if (item is not null)
+			{
+				result.Add(item);
+			}
 		}
 		return result;
 	}
@@ -452,7 +460,9 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 				int index = 0;
 				foreach (var nativeItem in itemList)
 				{
-					if (nativeItem is ItemTemplateContext2 itemPair && ItemsView.SelectedItems.Contains(itemPair.Item))
+					if (nativeItem is ItemTemplateContext2 itemPair &&
+						itemPair.EntryKind == ItemTemplateContextKind2.Item &&
+						ItemsView.SelectedItems.Contains(itemPair.Item))
 					{
 						PlatformView.Select(index);
 					}
@@ -480,16 +490,40 @@ public partial class CollectionViewHandler2 : ReorderableItemsViewHandler2<Reord
 	static int FindItemIndexInSource(ICollectionView itemList, object targetItem)
 	{
 		int index = 0;
+		int valueEqualFallback = -1;
 		foreach (var nativeItem in itemList)
 		{
-			var actualItem = nativeItem is ItemTemplateContext2 itc ? itc.Item : nativeItem;
-			if (object.Equals(actualItem, targetItem))
+			if (nativeItem is ItemTemplateContext2 itc)
+			{
+				if (itc.EntryKind != ItemTemplateContextKind2.Item)
+				{
+					index++;
+					continue;
+				}
+
+				if (ReferenceEquals(itc.Item, targetItem))
+				{
+					return index;
+				}
+
+				if (valueEqualFallback < 0 && object.Equals(itc.Item, targetItem))
+				{
+					valueEqualFallback = index;
+				}
+			}
+			else if (ReferenceEquals(nativeItem, targetItem))
 			{
 				return index;
 			}
+			else if (valueEqualFallback < 0 && object.Equals(nativeItem, targetItem))
+			{
+				valueEqualFallback = index;
+			}
+
 			index++;
 		}
-		return -1;
+
+		return valueEqualFallback;
 	}
 }
 
diff --git a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
index 8f0640c723..40db60548d 100644
--- a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.Windows.cs
@@ -1875,6 +1875,11 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 			return -1;
 		}
 
+		if (_collectionViewSource.Source is GroupedItemTemplateCollection2 groupedCollection)
+		{
+			return groupedCollection.FindGroupedEntryIndex(item, group);
+		}
+
 		if (ItemsView is not GroupableItemsView groupableItemsView)
 		{
 			return -1;
@@ -1901,7 +1906,7 @@ public abstract class ItemsViewHandler2<TItemsView> : ViewHandler<TItemsView, WI
 				continue;
 			}
 
-			if (Equals(g, group))
+			if (ReferenceEquals(g, group))
 			{
 				targetGroupItems = groupList;
 				flatIndexOfGroup = currentFlatIndex;
diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs b/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
index 1a28430592..58f3d9c79b 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/GroupedItemTemplateCollection2.cs
@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
-using System.Linq;
 
 namespace Microsoft.Maui.Controls.Handlers.Items2;
 /// <summary>
@@ -48,17 +47,20 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		}
 	}
 
-	ItemTemplateContext2 CreateItemContext(object item) =>
-		new(_itemTemplate, item, _container, mauiContext: _mauiContext);
+	ItemTemplateContext2 CreateItemContext(object? item, object group, int groupItemIndex) =>
+		new(_itemTemplate, item, _container, mauiContext: _mauiContext,
+			group: group, groupItemIndex: groupItemIndex, entryKind: ItemTemplateContextKind2.Item);
 
 	ItemTemplateContext2? CreateHeaderContext(object group) =>
 		_groupHeaderTemplate is not null
-			? new(_groupHeaderTemplate, group, _container, null, null, null, isHeader: true, isFooter: false, mauiContext: _mauiContext)
+			? new(_groupHeaderTemplate, group, _container, null, null, null, isHeader: true, isFooter: false,
+				mauiContext: _mauiContext, group: group, entryKind: ItemTemplateContextKind2.Header)
 			: null;
 
 	ItemTemplateContext2? CreateFooterContext(object group) =>
 		_groupFooterTemplate is not null
-			? new(_groupFooterTemplate, group, _container, null, null, null, isHeader: false, isFooter: true, mauiContext: _mauiContext)
+			? new(_groupFooterTemplate, group, _container, null, null, null, isHeader: false, isFooter: true,
+				mauiContext: _mauiContext, group: group, entryKind: ItemTemplateContextKind2.Footer)
 			: null;
 
 	void SubscribeToGroups(IEnumerable? groups)
@@ -135,9 +137,10 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 				Items.Add(header);
 			}
 
+			int groupItemIndex = 0;
 			foreach (var item in itemsList)
 			{
-				Items.Add(CreateItemContext(item));
+				Items.Add(CreateItemContext(item, group, groupItemIndex++));
 			}
 
 			var footer = CreateFooterContext(group);
@@ -202,7 +205,7 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 				if (group is ICollection collection)
 					flatIndex += collection.Count;
 				else
-					flatIndex += items.Cast<object>().Count();
+					flatIndex += CountItems(items);
 
 				if (_groupFooterTemplate is not null)
 					flatIndex++;
@@ -229,19 +232,19 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		switch (e.Action)
 		{
 			case NotifyCollectionChangedAction.Add:
-				HandleGroupItemsAdd(e, flatIndex, groupList);
+				HandleGroupItemsAdd(e, flatIndex, groupList, group);
 				break;
 
 			case NotifyCollectionChangedAction.Remove:
-				HandleGroupItemsRemove(e, flatIndex);
+				HandleGroupItemsRemove(e, flatIndex, group);
 				break;
 
 			case NotifyCollectionChangedAction.Replace:
-				HandleGroupItemsReplace(e, flatIndex);
+				HandleGroupItemsReplace(e, flatIndex, group);
 				break;
 
 			case NotifyCollectionChangedAction.Move:
-				HandleGroupItemsMove(e, flatIndex);
+				HandleGroupItemsMove(e, flatIndex, group);
 				break;
 
 			case NotifyCollectionChangedAction.Reset:
@@ -250,7 +253,7 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		}
 	}
 
-	void HandleGroupItemsAdd(NotifyCollectionChangedEventArgs e, int flatIndex, IList groupList)
+	void HandleGroupItemsAdd(NotifyCollectionChangedEventArgs e, int flatIndex, IList groupList, object group)
 	{
 		if (e.NewItems is null)
 			return;
@@ -265,19 +268,21 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		var newItems = new List<ItemTemplateContext2>(e.NewItems.Count);
 
 		_suppressNotifications = true;
+		int groupItemIndex = e.NewStartingIndex >= 0 ? e.NewStartingIndex : groupList.Count - e.NewItems.Count;
 		foreach (var item in e.NewItems)
 		{
-			var newItem = CreateItemContext(item);
+			var newItem = CreateItemContext(item, group, groupItemIndex++);
 			newItems.Add(newItem);
 			Items.Insert(insertIndex++, newItem);
 		}
 		_suppressNotifications = false;
+		UpdateGroupItemIndices(group);
 
 		OnCollectionChanged(new NotifyCollectionChangedEventArgs(
 			NotifyCollectionChangedAction.Add, newItems, insertIndex - newItems.Count));
 	}
 
-	void HandleGroupItemsRemove(NotifyCollectionChangedEventArgs e, int flatIndex)
+	void HandleGroupItemsRemove(NotifyCollectionChangedEventArgs e, int flatIndex, object group)
 	{
 		if (e.OldItems is null)
 			return;
@@ -297,12 +302,13 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 			Items.RemoveAt(removeIndex);
 		}
 		_suppressNotifications = false;
+		UpdateGroupItemIndices(group);
 
 		OnCollectionChanged(new NotifyCollectionChangedEventArgs(
 			NotifyCollectionChangedAction.Remove, removedItems, removeIndex));
 	}
 
-	void HandleGroupItemsReplace(NotifyCollectionChangedEventArgs e, int flatIndex)
+	void HandleGroupItemsReplace(NotifyCollectionChangedEventArgs e, int flatIndex, object group)
 	{
 		if (e.NewItems is null || e.OldItems is null)
 			return;
@@ -317,24 +323,24 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		var newItems = new List<ItemTemplateContext2>(e.NewItems.Count);
 
 		_suppressNotifications = true;
+		int groupItemIndex = e.NewStartingIndex >= 0 ? e.NewStartingIndex : 0;
 		for (int i = 0; i < e.NewItems.Count; i++)
 		{
 			oldItems.Add(Items[replaceIndex + i]);
 			var item = e.NewItems[i];
-			if (item is null)
-				continue;
 
-			var newItem = CreateItemContext(e.NewItems[i]!);
+			var newItem = CreateItemContext(item, group, groupItemIndex++);
 			newItems.Add(newItem);
 			Items[replaceIndex + i] = newItem;
 		}
 		_suppressNotifications = false;
+		UpdateGroupItemIndices(group);
 
 		OnCollectionChanged(new NotifyCollectionChangedEventArgs(
 			NotifyCollectionChangedAction.Replace, newItems, oldItems, replaceIndex));
 	}
 
-	void HandleGroupItemsMove(NotifyCollectionChangedEventArgs e, int flatIndex)
+	void HandleGroupItemsMove(NotifyCollectionChangedEventArgs e, int flatIndex, object group)
 	{
 		if (e.OldItems is null)
 			return;
@@ -357,6 +363,7 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 			movedItems.Add(item);
 		}
 		_suppressNotifications = false;
+		UpdateGroupItemIndices(group);
 
 		// Fire Remove + Add instead of Move.
 		// CsWinRT translates CollectionChanged(Move) -> VectorChanged(Reset), which causes
@@ -380,6 +387,93 @@ internal class GroupedItemTemplateCollection2 : ObservableCollection<ItemTemplat
 		OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
 	}
 
+	internal int FindGroupedEntryIndex(object? item, object group)
+	{
+		int headerIndex = -1;
+		int firstItemIndex = -1;
+		int valueEqualFallback = -1;
+
+		for (int i = 0; i < Items.Count; i++)
+		{
+			var context = Items[i];
+			if (!ReferenceEquals(context.Group, group))
+			{
+				continue;
+			}
+
+			if (context.EntryKind == ItemTemplateContextKind2.Header)
+			{
+				headerIndex = i;
+				continue;
+			}
+
+			if (context.EntryKind != ItemTemplateContextKind2.Item)
+			{
+				continue;
+			}
+
+			if (firstItemIndex < 0)
+			{
+				firstItemIndex = i;
+			}
+
+			if (item is null)
+			{
+				continue;
+			}
+
+			if (ReferenceEquals(context.Item, item))
+			{
+				return i;
+			}
+
+			if (valueEqualFallback < 0 && Equals(context.Item, item))
+			{
+				valueEqualFallback = i;
+			}
+		}
+
+		if (item is null)
+		{
+			return headerIndex >= 0 ? headerIndex : firstItemIndex;
+		}
+
+		return valueEqualFallback;
+	}
+
+	static int CountItems(IEnumerable items)
+	{
+		int count = 0;
+		foreach (var item in items)
+		{
+			count++;
+		}
+		return count;
+	}
+
+	void UpdateGroupItemIndices(object group)
+	{
+		int groupItemIndex = 0;
+		for (int i = 0; i < Items.Count; i++)
+		{
+			var context = Items[i];
+			if (!ReferenceEquals(context.Group, group))
+			{
+				continue;
+			}
+
+			if (context.EntryKind == ItemTemplateContextKind2.Item)
+			{
+				context.UpdateGroupedEntry(group, groupItemIndex++, ItemTemplateContextKind2.Item);
+			}
+			else if (context.EntryKind == ItemTemplateContextKind2.Header ||
+				context.EntryKind == ItemTemplateContextKind2.Footer)
+			{
+				context.UpdateGroupedEntry(group, -1, context.EntryKind);
+			}
+		}
+	}
+
 	/// <summary>
 	/// Full reset that also resubscribes to all groups.
 	/// Used for Replace and Reset actions where group references may have changed.
diff --git a/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs b/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
index cd2c2837ca..9ae1e20bf8 100644
--- a/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/Windows/ItemTemplateContext2.cs
@@ -2,6 +2,13 @@
 
 namespace Microsoft.Maui.Controls.Handlers.Items2;
 
+internal enum ItemTemplateContextKind2
+{
+	Item,
+	Header,
+	Footer
+}
+
 /// <summary>
 /// Pairs a data item with its <see cref="DataTemplate"/> and layout metadata.
 /// Used by the WinUI ItemsView/ItemsRepeater as the data context for each realized element.
@@ -31,15 +38,25 @@ internal class ItemTemplateContext2
 	/// <summary>The spacing between items.</summary>
 	public Thickness ItemSpacing { get; }
 
+	/// <summary>The grouped entry kind represented by this context.</summary>
+	public ItemTemplateContextKind2 EntryKind { get; private set; }
+
 	/// <summary>Whether this context represents a group header.</summary>
-	public bool IsHeader { get; }
+	public bool IsHeader => EntryKind == ItemTemplateContextKind2.Header;
 
 	/// <summary>Whether this context represents a group footer.</summary>
-	public bool IsFooter { get; }
+	public bool IsFooter => EntryKind == ItemTemplateContextKind2.Footer;
+
+	/// <summary>The source group for grouped item contexts.</summary>
+	public object? Group { get; private set; }
+
+	/// <summary>The index of this data item within <see cref="Group"/>, or -1 for header/footer entries.</summary>
+	public int GroupItemIndex { get; private set; } = -1;
 
 	public ItemTemplateContext2(DataTemplate mauiDataTemplate, object? item, BindableObject container,
 		double? height = null, double? width = null, Thickness? itemSpacing = null,
-		bool isHeader = false, bool isFooter = false, IMauiContext? mauiContext = null)
+		bool isHeader = false, bool isFooter = false, IMauiContext? mauiContext = null,
+		object? group = null, int groupItemIndex = -1, ItemTemplateContextKind2 entryKind = ItemTemplateContextKind2.Item)
 	{
 		MauiDataTemplate = mauiDataTemplate;
 		Item = item;
@@ -49,7 +66,19 @@ internal class ItemTemplateContext2
 		ItemWidth = width ?? 0;
 		ItemSpacing = itemSpacing ?? default;
 
-		IsHeader = isHeader;
-		IsFooter = isFooter;
+		Group = group;
+		GroupItemIndex = groupItemIndex;
+		EntryKind = isHeader
+			? ItemTemplateContextKind2.Header
+			: isFooter
+				? ItemTemplateContextKind2.Footer
+				: entryKind;
+	}
+
+	internal void UpdateGroupedEntry(object group, int groupItemIndex, ItemTemplateContextKind2 entryKind)
+	{
+		Group = group;
+		GroupItemIndex = groupItemIndex;
+		EntryKind = entryKind;
 	}
 }

🏁 Report — Final Recommendation

Comparative Report — PR #34600

Testing signal

No candidate has a successful Windows regression run in the available artifacts. The raw PR gate is inconclusive, and every STEP 5a try-fix candidate was blocked before tests executed by the same NETSDK1005 missing net10.0-windows10.0.19041.0 target-assets environment issue. No candidate is ranked lower for failed regression tests because none recorded a regression-test failure.

Candidate comparison

Rank Candidate Test result Assessment
1 pr-plus-reviewer Inconclusive / unverified Best candidate. It preserves the PR's Windows CV2 architecture and applies the expert reviewer's three actionable fixes: enumerable grouped ScrollTo, null-preserving grouped Replace, and header/footer selection filtering.
2 try-fix-2 Blocked Strong focused fix for the grouped null Replace bug. Lower than pr-plus-reviewer because it does not address grouped ScrollTo or selection leakage.
3 try-fix-1 Blocked Strong focused fix for grouped ScrollTo with enumerable groups. Lower than pr-plus-reviewer because it does not address null Replace or selection leakage.
4 try-fix-5 Blocked Focused fix for selection filtering. Lower than pr-plus-reviewer because it does not address the two stronger grouped data-source issues.
5 try-fix-6 Blocked Broader grouped identity approach that partly overlaps ScrollTo/null/selection concerns, but it is more invasive and still leaves drag/selection identity coverage incomplete per its own notes.
6 try-fix-3 Blocked Addresses grouped drag/drop duplicate identity, but the expert review did not identify this as an actionable blocker in the current PR diff.
7 try-fix-4 Blocked Addresses realized element cleanup, but the expert review did not identify this as an actionable blocker in the current PR diff.
8 pr Inconclusive / unverified Raw PR remains valuable as the base implementation, but it has three unresolved expert-review major findings.

Winning candidate

pr-plus-reviewer wins. It keeps the submitted PR implementation and applies only targeted reviewer feedback for concrete correctness issues found against the PR diff. Because it is still a PR-derived fix, the winner manifest marks it as isPRFix: true and leaves candidateDiff empty.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 22, 2026
@kubaflo

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

@SuthiYuvaraj — test-failure review results are available based on commit 27171d2.
To request a fresh review after new comments, commits, or CI runs, comment /review tests.

Overall Likely unrelated Failures 7 Platform android Platform ios Platform mac

Test Failure Review: Likely unrelated - click to expand

Overall verdict: Likely unrelated

This PR is labeled platform/windows and all changed handler files are under Handlers/Items2/Windows/ — none of the failing jobs run on Windows. The net11.0 base branch has been consistently failing on both maui-pr (5/5 recent builds: 1475412, 1473152, 1472845, 1472462, 1470817) and maui-pr-uitests (multiple recent builds), indicating pre-existing infrastructure issues unrelated to this PR.

Failure Verdict Evidence
maui-pr (Run Integration Tests AOT macOS)PublishNativeAOTRootAllMauiAssemblies Likely unrelated ILC IL3050 warning in HybridWebViewHandler.SchemeHandler.Handler.get (RequiresDynamicCode); error message: "Unexpected warning files detected"; PR does not touch HybridWebViewHandler or AOT config; base branch failing on same definition for 5+ recent builds
maui-pr (Run Integration Tests RunOniOS_MauiReleaseTrimFull_CoreCLR ARM64)AppleTemplateTests.RunOniOS_MauiReleaseTrimFull_CoreCLR Likely unrelated iOS template build failure ("Project Testxxx.csproj failed to build"); PR is platform/windows with no iOS code changes; base branch also failing
maui-pr-uitests (Android CollectionView) Likely unrelated AzDO timeline records the Controls CollectionView task as cancelled (cascade from upstream phase failure); no Android CollectionView handler files changed; test results not published due to infra failure
maui-pr-uitests (Android SearchBar,Shape,Slider)DisplayAlertAsyncShouldNotCrashWhenPageUnloaded Likely unrelated Timeout (System.TimeoutException: Timed out waiting for element) in a DisplayAlert test within the SearchBar/Shape/Slider category; PR does not touch DisplayAlert; test results publication task also failed, indicating infrastructure instability
maui-pr-uitests (MacCatalyst Controls multiple jobs)Issue16918Test, ShellBadgeCanBeCleared/SetAtRuntime/InitialBadgeIsVisible/MultipleTabsCanHaveBadges Likely unrelated VisualTestUtils.VisualTestFailedException on MacCatalyst in Shell badge and unrelated visual tests; PR is Windows-only and does not touch MacCatalyst Shell badge or Issue16918; failures appear across two separate MacCatalyst runs (retries) suggesting persistent missing/mismatched baselines
maui-pr-uitests (iOS Shell) Likely unrelated iOS Shell UITest job; PR is platform/windows with no iOS/Shell changes
maui-pr-uitests (MacCatalyst CollectionView, Layout, Shell) — CANCELLED Likely unrelated Three MacCatalyst jobs cancelled as a cascade from the MacCatalyst stage failures above; no independent evidence of PR causation

Recommended action

No PR-caused failures were identified. All failures are on iOS/macOS/Android platforms in areas outside this Windows-only PR's scope, and the net11.0 base branch shows consistent pre-existing CI failures. Rerunning CI after a base-branch green build would confirm; the Shell badge visual failures on MacCatalyst may need baseline updates independently of this PR.

Evidence details

PR scope: 138 changed files, 113 test files; all platform-specific code is under src/Controls/src/Core/Handlers/Items2/Windows/ and src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs; labels: platform/windows, area-controls-collectionview. The only shared file changed is AppHostBuilderExtensions.cs, which adds CV2 handler registration gated behind a CollectionView2 feature flag, and RuntimeFeature.cs.

Build 1474985 (maui-pr): AzDO — 7 failed timeline records. AOT failure message: "Unexpected warning files detected! Unexpected warning file paths are: ILC" with `IL3050: Using member 'Microsoft.Maui.Handlers.HybridWebViewHandler.SchemeHandler.Handler.get' which has 'RequiresDynamicCode'". Recent base-branch builds on same definition: 1475412 (failed), 1473152 (failed), 1472845 (failed), 1472462 (failed), 1470817 (failed) — all failed, confirming pre-existing issue.

Build 1475001 (maui-pr-uitests): AzDO — 30 failed/cancelled timeline records. MacCatalyst visual test failures (VisualTestUtils.VisualTestFailedException) appear in 4 distinct ShellBadge* tests across multiple retries (occurrences: 2 per test). DisplayAlertAsyncShouldNotCrashWhenPageUnloaded timed out 4 times across retries. Recent base-branch builds: 1475414 (canceled), 1473225 (failed), 1472846 (failed), 1472463 (failed) — consistently failing.

Limitations: No AzDO bearer token was available; _apis/test endpoints were not queried. Build timelines and log excerpts were available via public API. Helix work-item data was not present in the gathered context. Device-test hidden failures (XHarness exit-0) could not be verified for maui-pr-devicetests (no such build was referenced in this CI run).

@PureWeen
PureWeen merged commit f15cbd8 into net11.0 Jun 22, 2026
132 of 147 checks passed
@PureWeen
PureWeen deleted the BugFixes_WinUI_CV2 branch June 22, 2026 22:44
@github-actions github-actions Bot added this to the .NET 11.0-preview6 milestone Jun 22, 2026
@SuthiYuvaraj
SuthiYuvaraj restored the BugFixes_WinUI_CV2 branch June 23, 2026 12:25
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 31, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView collectionview-winui-cv2 community ✨ Community Contribution p/0 Current heighest priority issues that we are targeting for a release. partner/syncfusion Issues / PR's with Syncfusion collaboration platform/windows 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.