[Windows] Fix for Grouping collection view without data template results in displaying the default string representation of the object#28617
Conversation
|
Hey there @SyedAbdulAzeemSF4852! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| IsSourceGrouped = true, | ||
| ItemsPath = new Microsoft.UI.Xaml.PropertyPath(nameof(GroupTemplateContext.Items)) | ||
| }; | ||
| return new CollectionViewSource |
There was a problem hiding this comment.
Can encapsulate the logic within separate methods for better readability:
private CollectionViewSource CreateGroupedCollectionViewSource(object itemsSource, object itemTemplate)
{
return new CollectionViewSource
{
Source = TemplatedItemSourceFactory.CreateGrouped(itemsSource, itemTemplate,
ItemsView.GroupHeaderTemplate, ItemsView.GroupFooterTemplate, Element, mauiContext: MauiContext),
IsSourceGrouped = true,
ItemsPath = new Microsoft.UI.Xaml.PropertyPath(nameof(GroupTemplateContext.Items))
};
}
// Creates and returns a grouped CollectionViewSource using itemsSource as the data source when an itemTemplate is not defined.
private CollectionViewSource CreateDefaultGroupedCollectionViewSource(object itemsSource)
{
return new CollectionViewSource
{
Source = itemsSource,
IsSourceGrouped = true,
};
}
return (itemTemplate is not null && itemsSource is not null)
? CreateGroupedCollectionViewSource(itemsSource, itemTemplate)
: CreateDefaultGroupedCollectionViewSource(itemsSource);
There was a problem hiding this comment.
@jsuarezruiz , As suggested have encapsulated the logic within separate methods for better readability.
| public void GroupedCollectionViewWithoutDataTemplate() | ||
| { | ||
| App.WaitForElement("CollectionViewWithoutDataTemplate"); | ||
| VerifyScreenshot(); |
There was a problem hiding this comment.
@jsuarezruiz , I have committed the snapshots.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| } | ||
| } | ||
|
|
||
| private CollectionViewSource CreateGroupedCollectionViewSource(IEnumerable itemsSource, DataTemplate itemTemplate) |
There was a problem hiding this comment.
Can we drop private we don t use it in our code base
There was a problem hiding this comment.
@rmarinho , As suggested, I've removed the private modifier.
| } | ||
|
|
||
| // Creates and returns a grouped CollectionViewSource using itemsSource as the data source when an itemTemplate is not defined. | ||
| private CollectionViewSource CreateDefaultGroupedCollectionViewSource(IEnumerable itemsSource) |
There was a problem hiding this comment.
| private CollectionViewSource CreateDefaultGroupedCollectionViewSource(IEnumerable itemsSource) | |
| CollectionViewSource CreateDefaultGroupedCollectionViewSource(IEnumerable itemsSource) |
There was a problem hiding this comment.
@rmarinho , I've made the changes as mentioned.
| } | ||
|
|
||
| // Creates and returns a grouped CollectionViewSource using itemsSource as the data source when an itemTemplate is not defined. | ||
| private CollectionViewSource CreateDefaultGroupedCollectionViewSource(IEnumerable itemsSource) |
There was a problem hiding this comment.
What happens if itemsSource is null?
There was a problem hiding this comment.
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
e70284c to
2b56ab2
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes a Windows-specific issue where CollectionView with grouping displays the default string representation (ToString()) of objects when no ItemTemplate is provided. The fix ensures that when an ItemTemplate is not specified, the data is bound directly without applying a default template that causes binding issues.
Key Changes:
- Modified the CollectionViewSource creation logic to handle grouped collections differently based on whether an ItemTemplate is provided
- Added two helper methods to distinguish between templated and non-templated grouped collection view scenarios
Reviewed changes
Copilot reviewed 3 out of 7 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Windows.cs | Refactored CollectionViewSource creation to conditionally apply templates, extracting logic into separate methods for templated vs. non-templated grouped collections |
| src/Controls/tests/TestCases.HostApp/Issues/Issue23293.cs | Added test case demonstrating grouped CollectionView without ItemTemplate using animal groups |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23293.cs | Added UI test to verify the fix via screenshot validation |
🤖 AI Summary📊 Expand Full Review —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #28617 | When grouping on Windows, use templated grouped source only when both itemTemplate and itemsSource are non-null; otherwise create a grouped CollectionViewSource directly from itemsSource without templates. |
PENDING (Gate) | src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Windows.cs, src/Controls/tests/TestCases.HostApp/Issues/Issue23293.cs, src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23293.cs, snapshot files |
Original PR |
🚦 Gate — Test Verification
Result: FAILED
Gate Result: FAILED
Platform: windows
Mode: Full Verification
- Tests FAIL without fix:
- Tests PASS with fix:
Notes
- Without the PR fix,
Issue23293.GroupedCollectionViewWithoutDataTemplatefailed as expected with a visual regression against the stored snapshot. - With the PR fix applied, the same verification failed on Windows with a timeout waiting for the target UI element.
- Gate conclusion: the test catches the bug, but the PR's current fix does not make the verification pass on the selected platform.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Move the no-template decision into TemplatedItemSourceFactory.CreateGrouped, returning raw grouped data when no item template exists, and let the Windows handler set ItemsPath only for GroupedItemTemplateCollection. |
PASS | 3 files | Passing alternative, but broader than candidate 2 because it changes both the factory and handler. |
| 2 | try-fix | Keep grouped wrapper behavior intact, but in GroupedItemTemplateCollection.CreateGroupTemplateContext expose raw group items when _itemTemplate is null instead of wrapping them in ItemTemplateContext. |
PASS | 1 code file + Windows snapshot | Strongest passing candidate: smallest production change and preserves the grouped wrapper pipeline. |
| 3 | try-fix | Change the default projection in TemplatedItemSourceFactory.Create for null templates and suppress wrapper text by overriding GroupTemplateContext.ToString(). |
FAIL | 2 files | Still produced a Windows screenshot mismatch (~4.09% difference). |
| 4 | try-fix | Introduce an interface so GroupTemplateContext can unwrap item-wrapper collections back to their original data source when ItemTemplate is null. |
FAIL | 4 files | Functionally close, but still failed visual verification (~4.09% difference). |
| 5 | try-fix | Inject an internal grouped fallback DataTemplate on Windows when ItemTemplate is null, while keeping grouped wrappers and ItemsPath intact. |
FAIL | 1 file | Avoided null-template data branching, but still produced the same ~4.09% screenshot mismatch. |
| 6 | try-fix | Use native DisplayMemberPath = nameof(ItemTemplateContext.Item) for grouped Windows items without an item template. |
PASS (weakened test) | 1 code file + 1 test file | Functional text-based check passed only after weakening the verification away from screenshot validation. |
| 7 | try-fix | Leave the data pipeline intact and instead route grouped null-template items through ItemContentControl, which renders a native fallback TextBlock when FormsDataTemplate is null. |
PASS | 2 production files + HostApp test data | Passed screenshot verification, but is broader than candidate 2 and reaches deeper into the rendering path. |
| PR | PR #28617 | Special-case grouped Windows CollectionViewSource creation in GroupableItemsViewHandler.Windows so templated grouping is used only when both itemTemplate and itemsSource are non-null, otherwise bind the raw grouped source directly. |
FAIL (Gate) | 3 code/test files + snapshots | Original PR times out on Windows during verification. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 1 | Yes | Factory-level grouped-source fallback plus adaptive handler ItemsPath passed. |
| claude-sonnet-4.6 | 1 | Yes | Grouped item materialization fallback inside GroupedItemTemplateCollection passed. |
| gpt-5.3-codex | 1 | Yes | Projection-layer passthrough plus GroupTemplateContext.ToString() failed. |
| gemini-3-pro-preview | 1 | Yes | Wrapper-unwrapping in GroupTemplateContext failed. |
| gpt-5.3-codex | 2 | Yes | Injecting a fallback grouped item template failed. |
| gemini-3-pro-preview | 2 | Yes | Native DisplayMemberPath passed only with weakened verification. |
| claude-sonnet-4.6 | 2 | Yes | Suggested rendering-layer fallback rather than another data-pipeline change. |
| claude-opus-4.6 | 2 | Yes | Suggested routing grouped null-template items through ItemContentControl; that approach passed as candidate 7. |
| gpt-5.3-codex | 3 | Yes | Proposed source-shaping to lightweight bindable objects; not run because stronger passing alternatives already existed. |
| gemini-3-pro-preview | 3 | Yes | Proposed ContainerContentChanging manual unwrapping; not run because stronger passing alternatives already existed. |
| claude-opus-4.6 | 3 | No | No new materially different ideas after comparing all seven attempts; passing strategies already cover the viable layers. |
| claude-sonnet-4.6 | 3 | Blocked | Timed out during final exhaustion query. |
Exhausted: No
Selected Fix: Candidate #2 Best balance of correctness, simplicity, and consistency. It fixes the grouped no-template case at the point where bad wrappers are created, without broad rendering-path changes or weakened verification.
📋 Report — Final Recommendation
Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | COMPLETE | Linked issue #23293 is Windows-only; PR changes one Windows handler plus UI test assets. |
| Gate | FAILED | Windows verification reproduced the bug without the fix, but the PR fix still failed with a timeout waiting for the target element. |
| Try-Fix | COMPLETE | 7 attempts: 3 strong passes, 1 weakened pass, 3 failures. Best alternative was candidate 2. |
| Report | COMPLETE |
Summary
The PR should not be merged in its current form. The gate showed that the new test catches the bug, but the PR's handler-level fix still fails on Windows. Independent exploration found multiple alternatives that do pass, which means the problem is fixable but the current implementation is not the best path.
Root Cause
The failure is tied to how Windows grouped CollectionView materializes or renders leaf items when ItemTemplate is null. The PR tries to bypass that by branching in GroupableItemsViewHandler.Windows, but verified Windows execution still times out. The strongest alternative fix instead addresses the grouped item materialization point directly by exposing raw group items when no template exists.
Fix Quality
The PR fix is not shippable as written because it fails the Windows gate. Candidate 2 is a better direction: it is smaller, stays within the existing grouped wrapper model, and passed validation without weakening the test. Candidate 7 also passed, but it is broader because it changes the rendering path and required more supporting adjustments.
📋 Expand PR Finalization Review
PR #28617 Finalization Review
Title Review
Current: [Windows] Fix for Grouping collection view without data template results in displaying the default string representation of the object
Assessment: Needs a tighter, more searchable title.
Recommended: [Windows] CollectionView: Fix grouped rendering without ItemTemplate
Why: the current title repeats the issue text verbatim and is harder to scan in git history. The recommended title keeps the platform + component prefix and describes the actual behavioral change.
Description Review
Assessment: Decent foundation, but not merge-ready as written.
What is good:
- Includes a real root-cause section.
- Includes a behavior description and issue link.
- Accurately frames the change as Windows-specific.
What should be updated:
- Add the required NOTE block at the very top from
.github/PULL_REQUEST_TEMPLATE.md. - Prefer the standard
### Description of Change/### Issues Fixedstructure instead of leading with### Issue Details. - Explicitly mention that the PR also adds UI coverage/snapshots for the reproduced scenario.
- If the implementation changes, update the description accordingly: the current text says the grouped source is created directly from
itemsSourcewhenitemTemplateis null, but that fallback currently appears to introduce a grouped header/footer regression risk.
Action: Keep the existing root-cause narrative, prepend the NOTE block, and revise the implementation details before merge.
Code Review Findings
Critical Issues
Grouped header/footer templates are likely regressed in the new Windows fallback path
- File:
src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Windows.cs - Problem: The new
CreateDefaultGroupedCollectionViewSource(IEnumerable itemsSource)path bypassesTemplatedItemSourceFactory.CreateGrouped(...)and returns the raw grouped source directly whenItemTemplateis null. - Why this matters: On Windows, grouped rendering relies on
GroupTemplateContextfor group metadata.GroupedItemTemplateCollectioncreates that wrapper and populatesHeaderItemTemplateContext/FooterItemTemplateContext(src/Controls/src/Core/Platform/Windows/CollectionView/GroupedItemTemplateCollection.cs,GroupTemplateContext.cs). The Windows group header template then binds itsDataContexttoHeaderItemTemplateContext(src/Controls/src/Core/Platform/Windows/CollectionView/ItemsViewStyles.xaml). If the source is raw groups instead ofGroupTemplateContext,GroupHeaderTemplate/GroupFooterTemplatecannot work correctly. - Evidence: Existing UI coverage already validates grouped header/footer behavior (
src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_GroupingFeatureTests.cs:250-308). Those scenarios depend on the same Windows group-template plumbing this fallback now skips. - Recommendation: Do not bypass the grouped wrapper. Preserve
TemplatedItemSourceFactory.CreateGrouped(...)/GroupTemplateContextfor grouped sources, and instead fix the no-ItemTemplatecase lower in the pipeline so group headers/footers continue to function.
Suggestions
- Add a targeted Windows test for the combination:
IsGrouped = true,ItemTemplate = null, andGroupHeaderTemplateand/orGroupFooterTemplateset. The new test page only covers the no-template grouped-items scenario, so it would not catch the regression above. - When the description is updated, mention that the fix is Windows handler code plus cross-platform UI snapshots, so reviewers do not misread the added screenshots as cross-platform behavior changes.
Looks Good
- The PR includes a focused reproduction page and a UI test for the reported issue (
Issue23293), which is the right level of coverage for the original bug. - The handler change is narrowly scoped to the Windows grouped CollectionView path.
Overall Assessment
The metadata needs a small cleanup, but the larger concern is the Windows grouped-template regression risk. I would not consider this PR ready to merge until the grouped no-ItemTemplate fix preserves GroupTemplateContext behavior for GroupHeaderTemplate / GroupFooterTemplate.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review -b feature/enhanced-reviewer |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 2 findings
See inline comments for details.
| // (GroupFooterItemTemplateContext) appended to each group's Items list needs a | ||
| // template to render correctly. Without a selector WinUI calls ToString() on it, | ||
| // displaying the class name instead of the bound footer content. | ||
| if (Element.ItemTemplate is null && ItemsView.IsGrouped && ItemsView.GroupFooterTemplate is not null) |
There was a problem hiding this comment.
[major] Handler Mapper and Property Patterns — This selector is only updated from UpdateItemTemplate(), but GroupFooterTemplate changes are mapped through MapIsGrouped, which only calls UpdateItemsSource(). Concrete scenario: a grouped Windows CollectionView starts with ItemTemplate == null, then sets GroupFooterTemplate after the handler is connected; the fake footer item is added to the source, but ItemTemplateSelector remains null, so WinUI renders the GroupFooterItemTemplateContext type name instead of the footer template. Please update this selector from the grouped/header/footer mapper path as well.
| { | ||
| // When no ItemTemplate is set, copy the raw group items into a new list so that: | ||
| // WinUI calls ToString() on the actual data objects (not on ItemTemplateContext wrappers). | ||
| var rawItems = new List<object>(); |
There was a problem hiding this comment.
[major] CollectionView Shared Models — Copying the group into a plain List<object> drops change notifications for observable groups when ItemTemplate is null. Previously, observable group lists flowed through ObservableItemTemplateCollection, which subscribed to the inner group's INotifyCollectionChanged; after this change, adding/removing items inside an ObservableCollection group will not update the Windows CollectionView. Please preserve a live/observable projection of the group items, especially for the no-footer case, or implement a wrapper that observes the source while still appending the synthetic footer without mutating user data.
kubaflo
left a comment
There was a problem hiding this comment.
Could you check the ai's suggestions?
|
/review -b feature/enhanced-reviewer -p windows |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
| // displaying the class name instead of the bound footer content. | ||
| if (Element.ItemTemplate is null && ItemsView.IsGrouped && ItemsView.GroupFooterTemplate is not null) | ||
| { | ||
| ListViewBase.ItemTemplateSelector = new GroupFooterDataTemplateSelector(); |
There was a problem hiding this comment.
[major] Handler Mapper and Property Patterns The footer selector is only updated from UpdateItemTemplate(), but GroupFooterTemplateProperty maps to MapIsGrouped/UpdateItemsSource() in GroupableItemsViewHandler.cs. Concrete scenario: a grouped CollectionView starts with no footer template and later sets GroupFooterTemplate; the source is rebuilt with synthetic GroupFooterItemTemplateContext rows, but ItemTemplateSelector is never installed, so the footer can still render as the context type name. Please update the grouped template mapper path to refresh this selector when GroupFooterTemplate changes, including clearing it when the footer template is removed.
| { | ||
| // When no ItemTemplate is set, copy the raw group items into a new list so that: | ||
| // WinUI calls ToString() on the actual data objects (not on ItemTemplateContext wrappers). | ||
| var rawItems = new List<object>(); |
There was a problem hiding this comment.
[major] CollectionView Windows Copying no-template group items into a new List<object> drops live INotifyCollectionChanged behavior for observable groups. Previously TemplatedItemSourceFactory.Create(...) returned ObservableItemTemplateCollection for IList + INCC, so adding/removing items inside a group could update the WinUI grouped source. With this snapshot list, ObservableCollection<string> groups will not reflect later item changes. Please preserve/forward the original group collection notifications while still exposing raw items for no-template rendering.
| public void GroupedCollectionViewWithoutItemTemplateRendersCorrectly() | ||
| { | ||
| App.WaitForElement("GroupFooterLabel"); | ||
| VerifyScreenshot(); |
There was a problem hiding this comment.
[major] Regression Prevention This new test calls VerifyScreenshot() and is intended to validate the Windows fix, but the PR only adds Android/iOS baselines. The known Windows gate failure is therefore a missing snapshots/windows/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png, so the Windows regression test cannot pass or protect this fix until the Windows baseline is committed.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review rerun |
|
/review -b feature/enhanced-reviewer -p windows |
This comment has been minimized.
This comment has been minimized.
Tests Failure Analysis
Test Failure Review: Insufficient data - click to expandOverall verdict: Insufficient data AzDO build 1367642 returned HTTP 404 and is inaccessible, so no log excerpts, timeline records, or test results could be retrieved. The two Windows Helix Unit Tests jobs were cancelled, which typically occurs when an upstream stage fails; all build and integration test jobs passed.
Recommended actionRerun the Evidence details
|
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
| // (GroupFooterItemTemplateContext) appended to each group's Items list needs a | ||
| // template to render correctly. Without a selector WinUI calls ToString() on it, | ||
| // displaying the class name instead of the bound footer content. | ||
| if (Element.ItemTemplate is null && ItemsView.IsGrouped && ItemsView.GroupFooterTemplate is not null) |
There was a problem hiding this comment.
[major] Handler Mapper and Property Patterns - The footer ItemTemplateSelector is only updated from UpdateItemTemplate(), but the condition also depends on IsGrouped and GroupFooterTemplate. On Windows those properties map through MapIsGrouped, which only rebuilds the items source, so dynamically setting GroupFooterTemplate or toggling IsGrouped after the handler is connected can create GroupFooterItemTemplateContext footer items while ListViewBase.ItemTemplateSelector remains null. Concrete scenario: create a grouped CollectionView without ItemTemplate, then assign GroupFooterTemplate later; the footer still renders as the context type name. Update this selector from the grouped/footer-template mapper path as well, or centralize it in a method called by both UpdateItemTemplate() and grouped-source updates.
| { | ||
| // When no ItemTemplate is set, copy the raw group items into a new list so that: | ||
| // WinUI calls ToString() on the actual data objects (not on ItemTemplateContext wrappers). | ||
| var rawItems = new List<object>(); |
There was a problem hiding this comment.
[major] CollectionView Shared Models - Copying no-template group contents into a new List<object> disconnects the displayed group items from observable inner groups. If a group implements INotifyCollectionChanged, additions/removals inside that group will no longer update the Windows CollectionView because WinUI is bound to the one-time copy plus fake footer, not the original observable source or an observable wrapper. Preserve inner collection notifications for the no-ItemTemplate path, especially when appending the footer item.
| public void GroupedCollectionViewWithoutItemTemplateRendersCorrectly() | ||
| { | ||
| App.WaitForElement("GroupFooterLabel"); | ||
| VerifyScreenshot(); |
There was a problem hiding this comment.
[major] Regression Prevention and Test Coverage - This shared UI test calls VerifyScreenshot() for a UWP/Windows-specific issue, but the PR adds only Android and iOS baselines. On WinUI the screenshot lookup will fail because snapshots/windows/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png is missing, which matches the observed gate failure after GroupFooterLabel appears. Add the Windows baseline or make the screenshot assertion platform-scoped.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the failing tests?
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
| { | ||
| // When no ItemTemplate is set, copy the raw group items into a new list so that: | ||
| // WinUI calls ToString() on the actual data objects (not on ItemTemplateContext wrappers). | ||
| var rawItems = new List<object>(); |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
❌ [major] CollectionView Windows regression — Copying the group into a detached List<object> drops live updates from observable groups when ItemTemplate is null. Before this path, observable IList groups went through ObservableItemTemplateCollection and nested adds/removes were proxied into WinUI; after this copy, adding an item to an ObservableCollection group updates the source but not the rendered group. Please keep an observable wrapper/projection for raw items instead of snapshotting the group.
| // (GroupFooterItemTemplateContext) appended to each group's Items list needs a | ||
| // template to render correctly. Without a selector WinUI calls ToString() on it, | ||
| // displaying the class name instead of the bound footer content. | ||
| if (Element.ItemTemplate is null && ItemsView.IsGrouped && ItemsView.GroupFooterTemplate is not null) |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
GroupFooterTemplate, but the GroupFooterTemplate mapper only calls UpdateItemsSource() (MapIsGrouped) and does not re-run UpdateItemTemplate(). If an app sets or clears GroupFooterTemplate after the handler is connected, the items source is rebuilt with footer contexts but ItemTemplateSelector can remain stale, so footers still render as GroupFooterItemTemplateContext (or the selector remains enabled after clearing). Please update this selector from the grouped/header/footer template mapper path as well.
| public void GroupedCollectionViewWithoutItemTemplateRendersCorrectly() | ||
| { | ||
| App.WaitForElement("GroupFooterLabel"); | ||
| VerifyScreenshot(); |
There was a problem hiding this comment.
🔍 AI-Generated Review (multi-model)
❌ [major] Regression test coverage — This Windows-specific screenshot test calls VerifyScreenshot(), but the PR adds only Android/iOS baselines. On Windows the test reaches this line and fails because the baseline image is missing, so the gate cannot validate the fix. Please add the Windows snapshot baseline or make the test platform-gated to the baselines that exist.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@SyedAbdulAzeemSF4852 — new AI review results are available based on this last commit:
de128d0. To request a fresh review after new comments or commits, comment/review rerun.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ❌ FAILED
Platform: WINDOWS · Base: main · Merge base: 6e107357
🩺 Fix does not pass the tests — every test still fails after applying the fix. The PR's change does not resolve the failure(s).
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue23293 Issue23293 |
✅ FAIL — 602s | ❌ FAIL — 485s |
🔴 Without fix — 🖥️ Issue23293: FAIL ✅ · 602s
Determining projects to restore...
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 44.56 sec).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 44.65 sec).
Restored D:\a\1\s\src\Controls\Foldable\src\Controls.Foldable.csproj (in 273 ms).
Restored D:\a\1\s\src\BlazorWebView\src\Maui\Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 3.67 sec).
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 25 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 17 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 57 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 20 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 3.92 sec).
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 23 ms).
Restored D:\a\1\s\src\Controls\tests\TestCases.HostApp\Controls.TestCases.HostApp.csproj (in 773 ms).
3 of 14 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Maps -> D:\a\1\s\artifacts\bin\Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> D:\a\1\s\artifacts\bin\Microsoft.AspNetCore.Components.WebView.Maui\Debug\net10.0-windows10.0.19041.0\Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
Controls.TestCases.HostApp -> D:\a\1\s\artifacts\bin\Controls.TestCases.HostApp\Debug\net10.0-windows10.0.19041.0\win-x64\Controls.TestCases.HostApp.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:11.60
Determining projects to restore...
Restored D:\a\1\s\src\TestUtils\src\VisualTestUtils\VisualTestUtils.csproj (in 813 ms).
Restored D:\a\1\s\src\TestUtils\src\UITest.NUnit\UITest.NUnit.csproj (in 1.58 sec).
Restored D:\a\1\s\src\TestUtils\src\UITest.Core\UITest.Core.csproj (in 4 ms).
Restored D:\a\1\s\src\TestUtils\src\VisualTestUtils.MagickNet\VisualTestUtils.MagickNet.csproj (in 4.44 sec).
Restored D:\a\1\s\src\TestUtils\src\UITest.Appium\UITest.Appium.csproj (in 2.17 sec).
Restored D:\a\1\s\src\TestUtils\src\UITest.Analyzers\UITest.Analyzers.csproj (in 8.44 sec).
Restored D:\a\1\s\src\Controls\tests\CustomAttributes\Controls.CustomAttributes.csproj (in 7 ms).
Restored D:\a\1\s\src\Controls\tests\TestCases.WinUI.Tests\Controls.TestCases.WinUI.Tests.csproj (in 8.13 sec).
7 of 15 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0\Microsoft.Maui.Graphics.dll
Controls.CustomAttributes -> D:\a\1\s\artifacts\bin\Controls.CustomAttributes\Debug\net10.0\Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0\Microsoft.Maui.dll
Controls.Core.Design -> D:\a\1\s\artifacts\bin\Controls.Core.Design\Debug\net472\Microsoft.Maui.Controls.DesignTools.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0\Microsoft.Maui.Controls.dll
UITest.Core -> D:\a\1\s\artifacts\bin\UITest.Core\Debug\net10.0\UITest.Core.dll
VisualTestUtils -> D:\a\1\s\artifacts\bin\VisualTestUtils\Debug\netstandard2.0\VisualTestUtils.dll
VisualTestUtils.MagickNet -> D:\a\1\s\artifacts\bin\VisualTestUtils.MagickNet\Debug\netstandard2.0\VisualTestUtils.MagickNet.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.dll
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
UITest.Analyzers -> D:\a\1\s\artifacts\bin\UITest.Analyzers\Debug\netstandard2.0\UITest.Analyzers.dll
Controls.TestCases.WinUI.Tests -> D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
Test run for D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/30/2026 2:56:33 PM FixtureSetup for Issue23293(Windows)
>>>>> 6/30/2026 2:56:46 PM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Start
>>>>> 6/30/2026 2:57:03 PM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Stop
>>>>> 6/30/2026 2:57:03 PM Log types:
Failed GroupedCollectionViewWithoutItemTemplateRendersCorrectly [17 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue23293.GroupedCollectionViewWithoutItemTemplateRendersCorrectly() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23293.cs:line 17
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 10.0.0)
[xUnit.net 00:00:00.12] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.36] Discovered: Controls.TestCases.WinUI.Tests
Results File: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue23293.trx
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 51.2496 Seconds
>>> TRX_RESULT_FILE: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue23293.trx
🟢 With fix — 🖥️ Issue23293: FAIL ❌ · 485s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Maps -> D:\a\1\s\artifacts\bin\Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Microsoft.AspNetCore.Components.WebView.Maui -> D:\a\1\s\artifacts\bin\Microsoft.AspNetCore.Components.WebView.Maui\Debug\net10.0-windows10.0.19041.0\Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
Controls.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
Controls.TestCases.HostApp -> D:\a\1\s\artifacts\bin\Controls.TestCases.HostApp\Debug\net10.0-windows10.0.19041.0\win-x64\Controls.TestCases.HostApp.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:01.24
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0\Microsoft.Maui.dll
Controls.CustomAttributes -> D:\a\1\s\artifacts\bin\Controls.CustomAttributes\Debug\net10.0\Controls.CustomAttributes.dll
Controls.Core.Design -> D:\a\1\s\artifacts\bin\Controls.Core.Design\Debug\net472\Microsoft.Maui.Controls.DesignTools.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529440
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0\Microsoft.Maui.Controls.dll
UITest.Core -> D:\a\1\s\artifacts\bin\UITest.Core\Debug\net10.0\UITest.Core.dll
VisualTestUtils -> D:\a\1\s\artifacts\bin\VisualTestUtils\Debug\netstandard2.0\VisualTestUtils.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.dll
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
VisualTestUtils.MagickNet -> D:\a\1\s\artifacts\bin\VisualTestUtils.MagickNet\Debug\netstandard2.0\VisualTestUtils.MagickNet.dll
UITest.Analyzers -> D:\a\1\s\artifacts\bin\UITest.Analyzers\Debug\netstandard2.0\UITest.Analyzers.dll
Controls.TestCases.WinUI.Tests -> D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
Test run for D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/30/2026 3:04:54 PM FixtureSetup for Issue23293(Windows)
>>>>> 6/30/2026 3:05:07 PM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Start
>>>>> 6/30/2026 3:05:09 PM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Stop
>>>>> 6/30/2026 3:05:09 PM Log types:
Failed GroupedCollectionViewWithoutItemTemplateRendersCorrectly [2 s]
Error Message:
VisualTestUtils.VisualTestFailedException :
Baseline snapshot not yet created: D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\snapshots\windows\GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png
Ensure new snapshot is correct: D:\a\1\a\Controls.TestCases.Shared.Tests\snapshots-diff\windows\GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png
and if it is, push a change to add it to the 'snapshots' directory.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
Stack Trace:
at VisualTestUtils.VisualRegressionTester.Fail(String message) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 162
at VisualTestUtils.VisualRegressionTester.VerifyMatchesSnapshot(String name, ImageSnapshot actualImage, String environmentName, ITestContext testContext) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 84
at Microsoft.Maui.TestCases.Tests.UITest.<VerifyScreenshot>g__Verify|13_0(String name, <>c__DisplayClass13_0&) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 477
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance, Boolean includeTitleBar) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 309
at Microsoft.Maui.TestCases.Tests.Issues.Issue23293.GroupedCollectionViewWithoutItemTemplateRendersCorrectly() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23293.cs:line 18
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 10.0.0)
[xUnit.net 00:00:00.12] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.38] Discovered: Controls.TestCases.WinUI.Tests
Results File: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue23293.trx
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 29.2887 Seconds
>>> TRX_RESULT_FILE: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue23293.trx
⚠️ Failure Details
- ❌ Issue23293 FAILED with fix (should pass)
GroupedCollectionViewWithoutItemTemplateRendersCorrectly [2 s]VisualTestUtils.VisualTestFailedException : Baseline snapshot not yet created: D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\snapshots\windows\GroupedCollectionViewWithoutItemT...
📁 Fix files reverted (2 files)
src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Windows.cssrc/Controls/src/Core/Platform/Windows/CollectionView/GroupedItemTemplateCollection.cs
New files (not reverted):
src/Controls/src/Core/Platform/Windows/CollectionView/GroupFooterDataTemplateSelector.cs
📱 UI Tests — CollectionView
Detected UI test categories: CollectionView
❌ Deep UI tests — 317 passed, 2 failed across 1 category on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
CollectionView |
317/330 (2 ❌) | 2 diff PNGs |
❌ CollectionView — 2 failed tests
GroupedCollectionViewWithoutItemTemplateRendersCorrectly
VisualTestUtils.VisualTestFailedException :
Baseline snapshot not yet created: D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\snapshots\windows\GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png
Ensure new snapshot is correct: D:\a\1\a\Controls.TestCases.Shared.Tests\snapshots-diff\windows\GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png
and if it is, push a change to add it to the 'snapshots' directory.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
at VisualTestUtils.VisualRegressionTester.Fail(String message) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 162
at VisualTestUtils.VisualRegressionTester.VerifyMatchesSnapshot(String name, ImageSnapshot actualImage, String environmentName, ITestContext testContext) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 84
at Microsoft.Maui.TestCases.Tests
...
VerifyDefaultScrollToRequested
VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: VerifyDefaultScrollToRequested.png (0.52% difference)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
at VisualTestUtils.VisualRegressionTester.Fail(String message) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 162
at VisualTestUtils.VisualRegressionTester.VerifyMatchesSnapshot(String name, ImageSnapshot actualImage, String environmentName, ITestContext testContext) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 123
at Microsoft.Maui.TestCases.Tests.UITest.<VerifyScreenshot>g__Verify|13_0(String name, <>c__DisplayClass13_0&) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 477
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 ret
...
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
📋 Pre-Flight — Context & Validation
Issue: #23293 - Grouping collection view without data template results in displaying the default string representation of the object
PR: #28617 - Windows grouped CollectionView without ItemTemplate renders item/footer content correctly
Platforms Affected: Windows
Files Changed: 3 implementation, 4 test
Key Findings
- PR targets Windows grouped CollectionView: regular grouped items are wrapped in
ItemTemplateContext, while fake group footers are represented byGroupFooterItemTemplateContext. - Current PR fix avoids wrapper rendering by copying raw group items when
ItemTemplateis null and templating only footer context rows. - Expert review identified a likely dynamic group item update regression from snapshotting group items into
List<object>. - Gate had already failed before this phase; gate verification was not re-run.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: low
Errors: 1 | Warnings: 2 | Suggestions: 0
Key code review findings:
- ✗
GroupedItemTemplateCollection.cs:82-97copies raw group items into a detached list, likely breaking liveINotifyCollectionChangedupdates inside groups. - ⚠
GroupableItemsViewHandler.Windows.cs:38-55updates the footerItemTemplateSelectoronly throughUpdateItemTemplate(), not dynamic footer/grouping mapper paths. - ⚠ The added screenshot baselines are Android/iOS, while the issue is Windows-specific.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #28617 | Snapshot raw grouped items when no ItemTemplate and use a footer-only template selector | ❌ FAILED (Gate pre-run) | GroupableItemsViewHandler.Windows.cs, GroupedItemTemplateCollection.cs, GroupFooterDataTemplateSelector.cs |
Original PR; local review found dynamic-update risks |
🔬 Code Review — Deep Analysis
Code Review — PR #28617
Independent Assessment
What this changes: The PR changes Windows grouped CollectionView data shaping when ItemTemplate is null. It stops wrapping regular grouped items in ItemTemplateContext by copying raw group items into a List<object>, and adds a footer-only DataTemplateSelector so fake GroupFooterItemTemplateContext rows still use ItemsViewDefaultTemplate.
Inferred motivation: In grouped Windows CollectionView, WinUI default rendering sees wrapper objects and fake footer objects, so without an item template it renders type names rather than item text/footer template content.
Reconciliation with PR Narrative
Author claims: GitHub context unavailable because gh is unauthenticated. The local test issue and commit indicate issue #23293: grouped CollectionView without a data template displays default string representations/class names.
Agreement/disagreement: The code addresses the apparent root cause for initial rendering, but the implementation risks losing live group-item updates and has selector-state gaps when footer/grouping properties change dynamically.
Prior Review Reconciliation
No prior ❌ Error findings found locally; GitHub review/comment surfaces could not be queried because gh requires authentication.
Blast Radius Assessment
- Runs for all instances: No, scoped to Windows grouped
CollectionView, but it runs for every grouped source creation and item-template update. - Startup impact: No direct app startup impact.
- Static/shared state: No new static state.
CI Status
- Required-check result: undetermined
- Classification: undetermined;
ghis unavailable/unauthenticated in this environment. - Action taken: confidence capped low; final code-review verdict cannot be LGTM based solely on local code review.
Findings
❌ Error — Raw copied grouped items break live item updates
src/Controls/src/Core/Platform/Windows/CollectionView/GroupedItemTemplateCollection.cs:82-97 copies group items into a detached List<object> whenever _itemTemplate is null. The previous TemplatedItemSourceFactory.Create() path returned ObservableItemTemplateCollection for IList + INotifyCollectionChanged, preserving add/remove/replace/reset notifications from each group. A grouped ObservableCollection<T> can now render correctly initially but fail to update when items change after load.
⚠️ Warning — Footer selector is not refreshed for dynamic footer/grouping changes
src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Windows.cs:38-55 installs GroupFooterDataTemplateSelector only from UpdateItemTemplate(). The mapper for IsGrouped, GroupFooterTemplate, and GroupHeaderTemplate calls MapIsGrouped, which only updates the item source. Setting GroupFooterTemplate after handler creation can create footer contexts while leaving ItemTemplateSelector null.
⚠️ Warning — No Windows screenshot baseline in this diff
The issue is marked Windows/UWP-specific, but the local diff adds Android and iOS baselines and no Windows snapshot. The test may not validate the actual target platform in CI.
Failure-Mode Probing
- Observable group changes after first render: current PR likely misses inner collection updates because it snapshots group items into a new list when no item template is set.
- Dynamic
GroupFooterTemplateassignment: current PR can leave the selector stale because footer template changes map throughMapIsGrouped, notUpdateItemTemplate(). - Grouped collection without footer: regular items render raw values under the PR approach, but at the cost of lazy/observable wrapper behavior.
Verdict: NEEDS_CHANGES
Confidence: low
Summary: The root cause is valid, but the current implementation trades the wrapper rendering bug for likely dynamic update regressions in Windows grouped CollectionView. GitHub/CI state was unavailable, so this verdict is based on local diff analysis and MAUI Windows CollectionView code paths.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Preserve ItemTemplateContext wrappers, add ToString() delegation, refresh footer selector dynamically |
❌ FAIL | ItemTemplateContext.cs, GroupableItemsViewHandler.Windows.cs, PublicAPI/net-windows/PublicAPI.Unshipped.txt |
Build passed after PublicAPI entry; Windows UI test failed because no Windows snapshot baseline exists |
| 2 | try-fix | Preserve wrappers and add explicit grouped-item DataTemplateSelector/XAML template binding to ItemTemplateContext.Item |
❌ FAIL | GroupableItemsViewHandler.Windows.cs, GroupFooterDataTemplateSelector.cs, ItemsViewStyles.xaml |
Build passed; Windows UI test failed because no Windows snapshot baseline exists |
| 3 | try-fix | Use live raw IList adapter with virtual footer instead of snapshotting group items |
❌ FAIL | GroupedItemTemplateCollection.cs, RawGroupItemSourceWithFooter.cs, GroupableItemsViewHandler.Windows.cs |
Build passed; Windows UI test failed because no Windows snapshot baseline exists; self-review found adapter complexity/disposal risk |
| 4 | try-fix | Render synthetic footer at WinUI container level instead of via ItemTemplateSelector |
❌ FAIL | GroupFooterItemTemplateContext.cs, FormsListView.cs, FormsGridView.cs, GroupedItemTemplateCollection.cs |
Build passed after a compile fix, but test failed with app/window crash (NoSuchWindowError) |
| PR | PR #28617 | Snapshot raw grouped items when no ItemTemplate and use footer-only ItemTemplateSelector |
❌ FAILED (Gate) | 3 implementation files | Original PR; local review found likely dynamic grouped item update regression |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Suggested wrapper-preserving ToString(), explicit grouped item selector, and live raw grouped-items adapter approaches |
| maui-expert-reviewer | 2 | Yes | Suggested container-level footer templating in FormsListView/FormsGridView as a distinct footer-only strategy |
| maui-expert-reviewer | 3 | No | After trying the container-level strategy, remaining meaningful approaches were exhausted; further variants would be test-asset fixes or minor selector/adapter variations |
Exhausted: Yes
Selected Fix: None — no candidate passed all tests. Candidates #1 and #2 appear technically more robust than the PR because they preserve the existing observable/lazy grouped item wrapper pipeline, but both are blocked by the missing Windows screenshot baseline in the current UI test. Candidate #4 is rejected because it caused an app/window crash. Candidate #3 is rejected as too complex/risky for servicing despite addressing the PR's detached-list issue.
Failure Lessons
- The repeated Windows UI failure for candidates #1-#3 is not a code assertion failure; it is missing test data:
snapshots/windows/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.pngis absent. - The PR's test assets are incomplete for the requested
windowsplatform even though the issue is Windows-specific. - The current PR fix likely regresses dynamic grouped item updates by copying group items into a detached
List<object>when noItemTemplateis set. - The safest alternative direction is either candidate #1 (wrapper
ToString()+ PublicAPI entry) or candidate #2 (explicit wrapper template selector), but either needs a Windows baseline/assertion test fix before it can pass the requested gate criteria.
📝 Recommended PR Title & Description
Assessment: ✏️ Recommend updating — the current description matches the raw PR, but the winning pr-plus-reviewer candidate changes the implementation approach by preserving ItemTemplateContext wrappers with ToString() delegation, updating selector lifecycle handling, and adding the missing Windows baseline.
Recommended title
[Windows] CollectionView: Fix grouped items and footers without ItemTemplate
Recommended description
### Issue Details
- Grouping CollectionView without an ItemTemplate can display the default string representation of internal wrapper objects instead of the grouped item/footer content.
### Root Cause
- On Windows, grouped CollectionView items are represented through `ItemTemplateContext` wrappers, and synthetic group footers use `GroupFooterItemTemplateContext` because WinUI ListViewBase does not provide native group footer support.
- When no `ItemTemplate` is specified, WinUI falls back to `ToString()`. Without special handling, it can call `ToString()` on MAUI wrapper/context objects instead of the underlying grouped item or footer content.
### Description of Change
- In `GroupableItemsViewHandler.Windows.cs`, update `UpdateItemTemplate()` and the grouped mapper path so the footer-only `GroupFooterDataTemplateSelector` is kept in sync when grouping or group footer/header template properties change.
- Add `GroupFooterDataTemplateSelector` to apply `ItemsViewDefaultTemplate` only to synthetic `GroupFooterItemTemplateContext` rows, letting normal grouped items use WinUI fallback rendering.
- In `ItemTemplateContext`, delegate `ToString()` to the wrapped `Item` so grouped CollectionView items without an `ItemTemplate` render the actual item text while preserving the existing observable wrapper pipeline.
- Keep grouped item lists live instead of copying them into detached raw lists, so observable group contents continue to update correctly.
- Add the Windows visual regression baseline for `GroupedCollectionViewWithoutItemTemplateRendersCorrectly`.
### Validated the behaviour in the following platforms
- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac
### Issues Fixed
Fixes #23293
### Output
| Before Fix | After Fix |
|----------|----------|
| <video src="https://github.com/user-attachments/assets/e1881d44-3794-4ac8-9893-c356c0d069e3"> | <video src="https://github.com/user-attachments/assets/1fe00d1c-097b-4b1e-b086-723f0eea15a9"> |
🏁 Report — Final Recommendation
Comparative Report — PR #28617
Ranking
| Rank | Candidate | Test result | Assessment |
|---|---|---|---|
| 1 | pr-plus-reviewer |
Not re-run; based on STEP 5a evidence plus sandbox-applied reviewer fixes | Best candidate. Preserves observable grouped item behavior, fixes stale footer selector state, and completes the Windows snapshot asset missing from the PR gate. |
| 2 | try-fix-1 |
❌ Failed on missing Windows snapshot baseline | Strongest STEP 5a alternative. Preserves wrappers and delegates ItemTemplateContext.ToString() to the wrapped item; built successfully and only hit the missing Windows baseline, but did not include the full reviewer-applied PR/test asset set. |
| 3 | try-fix-2 |
❌ Failed on missing Windows snapshot baseline | Preserves wrapper behavior with an explicit selector/template for untemplated grouped items. Sound direction, but adds a new XAML resource and still lacked the Windows baseline. |
| 4 | try-fix-3 |
❌ Failed on missing Windows snapshot baseline | Addresses the PR snapshot regression with a live raw item adapter, but carries more complexity and disposal/change-proxy risk than the wrapper-preserving approaches. |
| 5 | pr |
❌ Gate failed | Fixes the immediate footer rendering enough to reach screenshot comparison, but has two blocking issues: nested observable group item updates are likely broken by the detached List<object> copy, and the Windows-specific screenshot baseline is missing. |
| 6 | try-fix-4 |
❌ Failed with app/window crash | Rejected. Container-level footer templating caused app/window instability (NoSuchWindowError), making it worse than the other failed candidates. |
Key comparison points
Regression-test rule: No candidate has a recorded passing gate result. try-fix-4 failed with a runtime/app crash and is therefore ranked last. pr, try-fix-1, try-fix-2, and try-fix-3 all failed at least partly because the Windows screenshot baseline was absent; among those, candidates that preserve the existing observable wrapper pipeline rank above candidates that snapshot or introduce high-risk adapters.
Raw PR (pr): The PR's GroupFooterDataTemplateSelector is a reasonable way to template only synthetic group footer rows. However, GroupedItemTemplateCollection now copies untemplated group items into a detached list, which removes the live nested collection behavior that ObservableItemTemplateCollection provided. The PR also adds Android/iOS snapshots but no Windows baseline even though the issue and requested testing platform are Windows.
Reviewer-applied PR (pr-plus-reviewer): This candidate keeps the PR's footer selector idea, but replaces the risky raw-list snapshot with ItemTemplateContext.ToString() delegation so WinUI's fallback string rendering shows the underlying item while preserving existing observable item source mechanics. It also updates the selector from the grouped mapper path and adds the missing Windows baseline artifact.
STEP 5a alternatives: try-fix-1 is the closest independent approach to pr-plus-reviewer and is the best pure try-fix candidate. try-fix-2 is also viable but adds an extra XAML template/selector path. try-fix-3 solves the live-update concern but with a custom adapter that is riskier in a hot CollectionView path. try-fix-4 is empirically unsafe due to the crash.
Winner
Winner: pr-plus-reviewer
pr-plus-reviewer is the single best candidate because it combines the PR's narrow footer templating fix with the expert review corrections needed for correctness: it avoids detaching live grouped item collections, keeps selector state synchronized with grouped template changes, and supplies the missing Windows screenshot baseline. Although it was not re-run as a gate, it is strictly stronger than the raw PR and the failed STEP 5a candidates based on the available evidence.
🧭 Next Steps — review latest findings
No alternative fix was selected for this run. Review the session findings and CI results before merging.

Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
Root Cause
Description of Change
Validated the behaviour in the following platforms
Issues Fixed
Fixes #23293
Output
Before.mp4
After.mp4