[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 apply the AI's suggestions?
kubaflo
left a comment
There was a problem hiding this comment.
Looks like the test is failing
#34575) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Adds Windows platform support to the `maui-copilot` CI pipeline (AzDO definition 27723), enabling Copilot PR reviews on Windows-targeted PRs. ### Changes **`eng/pipelines/ci-copilot.yml`** - Add `catalyst` and `windows` to Platform parameter values - Add per-platform pool selection (`androidPool`, `iosPool`, `macPool`, `windowsPool`) - Skip Xcode, Android SDK, simulator setup for Windows/Catalyst - Add Windows-specific "Set screen resolution" step (1920x1080) - Add MacCatalyst-specific "Disable Notification Center" step - Fix `sed` command for `Directory.Build.Override.props` on Windows (Git Bash uses GNU sed) - Handle Copilot CLI PATH detection on Windows vs Unix - Change `script:` steps to `bash:` for cross-platform consistency **`.github/scripts/Review-PR.ps1`** - Add `catalyst` to ValidateSet for Platform parameter **`.github/scripts/BuildAndRunHostApp.ps1`** - Add Windows test assembly directory for artifact collection **`.github/scripts/post-ai-summary-comment.ps1` / `post-pr-finalize-comment.ps1`** - Various improvements for cross-platform comment posting ### Validation Successfully ran the pipeline with `Platform=windows` on multiple Windows-specific PRs: - PR #27713 — ✅ Succeeded - PR #34337 — ✅ Succeeded - PR #26217, #27609, #27880, #28617, #29927, #30068 — Triggered and running --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…plates' page loading exception ).
…plates' page loading exception ).
…plates' page loading exception ).
…plates' page loading exception ).
…plates' page loading exception ).
…plates' page loading exception ).
…te results in displaying the default string representation of the object)
…te results in displaying the default string representation of the object)
…te results in displaying the default string representation of the object)
…te results in displaying the default string representation of the object)
…te results in displaying the default string representation of the object)
…te results in displaying the default string representation of the object)
2b56ab2 to
b3cef0c
Compare
|
🚀 Dogfood this PR with:
curl -fsSL https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 28617Or
iex "& { $(irm https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 28617" |
…napshots for iOS and Android
@kubaflo, I’ve updated the fix and modified the test case based on the suggestions provided by Mauibot. |
🚦 Gate — Test Before and After Fix
🚦 Gate Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue23293 Issue23293 |
✅ FAIL — 614s | ❌ FAIL — 486s |
🔴 Without fix — 🖥️ Issue23293: FAIL ✅ · 614s
Determining projects to restore...
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 50.69 sec).
Restored D:\a\1\s\src\BlazorWebView\src\Maui\Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 50.78 sec).
Restored D:\a\1\s\src\Controls\Foldable\src\Controls.Foldable.csproj (in 2.11 sec).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 2.8 sec).
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 7 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 14 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 34 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 16 ms).
Restored D:\a\1\s\src\Controls\tests\TestCases.HostApp\Controls.TestCases.HostApp.csproj (in 502 ms).
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 20 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 2.49 sec).
3 of 14 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
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.70-ci+azdo.13867198
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
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.14
Determining projects to restore...
Restored D:\a\1\s\src\TestUtils\src\VisualTestUtils\VisualTestUtils.csproj (in 935 ms).
Restored D:\a\1\s\src\TestUtils\src\UITest.NUnit\UITest.NUnit.csproj (in 1.57 sec).
Restored D:\a\1\s\src\TestUtils\src\UITest.Core\UITest.Core.csproj (in 3 ms).
Restored D:\a\1\s\src\TestUtils\src\UITest.Appium\UITest.Appium.csproj (in 1.21 sec).
Restored D:\a\1\s\src\TestUtils\src\UITest.Analyzers\UITest.Analyzers.csproj (in 4.91 sec).
Restored D:\a\1\s\src\TestUtils\src\VisualTestUtils.MagickNet\VisualTestUtils.MagickNet.csproj (in 12.02 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 4.71 sec).
7 of 15 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
Controls.CustomAttributes -> D:\a\1\s\artifacts\bin\Controls.CustomAttributes\Debug\net10.0\Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
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
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.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.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.
D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
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
>>>>> 4/17/2026 9:32:36 AM FixtureSetup for Issue23293(Windows)
>>>>> 4/17/2026 9:32:50 AM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Start
>>>>> 4/17/2026 9:33:05 AM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Stop
>>>>> 4/17/2026 9:33:05 AM Log types:
Failed GroupedCollectionViewWithoutItemTemplateRendersCorrectly [16 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.13] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.32] Discovered: Controls.TestCases.WinUI.Tests
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 54.4364 Seconds
🟢 With fix — 🖥️ Issue23293: FAIL ❌ · 486s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
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.70-ci+azdo.13867198
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
Controls.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.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:05:59.37
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13867198
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.70-ci+azdo.13867198
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
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.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.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.
D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
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
>>>>> 4/17/2026 9:40:58 AM FixtureSetup for Issue23293(Windows)
>>>>> 4/17/2026 9:41:10 AM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Start
>>>>> 4/17/2026 9:41:12 AM GroupedCollectionViewWithoutItemTemplateRendersCorrectly Stop
>>>>> 4/17/2026 9:41:12 AM 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.15] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.36] Discovered: Controls.TestCases.WinUI.Tests
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 32.1194 Seconds
⚠️ Issues found
- ❌ 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
🤖 AI Summary
📊 Review Session —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #28617 | Expose raw group items in GroupedItemTemplateCollection when no ItemTemplate; add GroupFooterDataTemplateSelector to route footer items through ItemsViewDefaultTemplate | ❌ FAIL (Gate — missing Windows snapshot) | 3 impl files + 4 test/snapshot files | Functionally the element appears; gate fails only on missing snapshot |
🔬 Code Review — Deep Analysis
Code Review — PR #28617
Independent Assessment
What this changes: Three coordinated changes on Windows for grouped CollectionView with no ItemTemplate:
GroupedItemTemplateCollection.cs: When_itemTemplateisnull, the group items list is now built as a rawList<object>(actual data objects) rather than going throughTemplatedItemSourceFactory. TheGroupFooterItemTemplateContextfake-footer item is still appended byGroupTemplateContext's constructor.GroupableItemsViewHandler.Windows.cs:UpdateItemTemplate()now setsListViewBase.ItemTemplateSelector = new GroupFooterDataTemplateSelector()whenItemTemplateis null, the view is grouped, and aGroupFooterTemplateis present. Otherwise it clears the selector.GroupFooterDataTemplateSelector.cs(new): ADataTemplateSelectorthat returnsItemsViewDefaultTemplateonly forGroupFooterItemTemplateContextitems andnullfor everything else.
Inferred motivation: On Windows, when no ItemTemplate is set, TemplatedItemSourceFactory.Create() wraps each item in an ItemTemplateContext. WinUI then calls ToString() on the ItemTemplateContext wrapper (showing the class name) rather than on the raw data object. The fix bypasses the wrapper by passing raw items, while still routing the fake footer item through the existing ItemsViewDefaultTemplate.
Reconciliation with PR Narrative
Author claims: The issue is that without an ItemTemplate, a default template causes binding failures and ToString() fallback on wrapper objects. Fixed by: (1) a custom DataTemplateSelector for footer items, (2) raw list for item data, (3) validated on Windows, Android, iOS, Mac.
Agreement: The root cause analysis and fix direction match the code. The fix is correct for the static configuration described in the issue. One area of disagreement/concern: the PR states the fix is "platform/windows" labeled but provides only Android/iOS snapshot baselines, not Windows.
Findings
⚠️ Warning — _footerTemplate silently falls back to the old bug if the resource isn't found
GroupFooterDataTemplateSelector.cs:16:
_footerTemplate = UWPApp.Current.Resources["ItemsViewDefaultTemplate"] as UWPDataTemplate;If the as cast fails (resource key not found, or resource dictionary not yet merged), _footerTemplate is null. SelectTemplateCore then reaches:
return _footerTemplate!; // NullReferenceException at runtime, or silent null if WinUI handles nullThe ! suppressor tells the compiler to trust the field is non-null, but it isn't. In practice WinUI's DataTemplateSelector path may handle a null return for the footer item gracefully — meaning the footer silently falls back to ToString() on the class name, reproducing the original bug with no diagnostic. A null-guard + Debug.Fail/warning log would catch this during development:
if (_footerTemplate is null)
System.Diagnostics.Debug.Fail("ItemsViewDefaultTemplate resource not found; group footers will not render.");⚠️ Warning — ItemTemplateSelector is not updated when GroupFooterTemplate changes dynamically
In GroupableItemsViewHandler.cs, GroupFooterTemplateProperty is mapped to MapIsGrouped:
[GroupableItemsView.GroupFooterTemplateProperty.PropertyName] = MapIsGrouped,MapIsGrouped calls handler.UpdateItemsSource() — not UpdateItemTemplate(). The new ItemTemplateSelector logic lives exclusively in UpdateItemTemplate(). This means:
Scenario: IsGrouped=true, ItemTemplate=null, GroupFooterTemplate initially null → user later sets GroupFooterTemplate:
UpdateItemsSource()is called →GroupedItemTemplateCollectioncorrectly appends aGroupFooterItemTemplateContext.UpdateItemTemplate()is not called →ListViewBase.ItemTemplateSelectorremainsnull.- WinUI calls
ToString()onGroupFooterItemTemplateContext→ class name displayed (original bug).
The static setup at construction time works correctly because UpdateItemsLayout() → UpdateItemTemplate() → UpdateItemsSource() in that order. But the dynamic scenario is incomplete. At minimum, a // TODO comment in UpdateItemTemplate acknowledging this limitation would help the next maintainer, or MapGroupFooterTemplate could also call UpdateItemTemplate().
⚠️ Warning — CI: maui-pr check is FAILING
maui-pr → FAILURE
maui-pr (Run Helix Unit Tests Windows Helix Unit Tests (Debug)) → CANCELLED
maui-pr (Run Helix Unit Tests Windows Helix Unit Tests (Release)) → CANCELLED
All build and integration jobs are green. The Helix Windows unit tests are cancelled, not failed, which suggests a CI infrastructure issue (queue timeout, capacity). This may be pre-existing and not caused by this PR. Worth confirming before merge.
💡 Suggestion — No Windows snapshot baseline for a Windows-specific fix
[Issue(..., PlatformAffected.UWP)] but only Android and iOS baselines are committed:
snapshots/android/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png✅snapshots/ios/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png✅snapshots/windows/GroupedCollectionViewWithoutItemTemplateRendersCorrectly.png❌ missing
The WaitForElement("GroupFooterLabel") call verifies the footer exists on Windows, which provides functional proof. But there's no screenshot regression baseline for Windows. If Windows UI tests aren't run in this pipeline, a note explaining why would help.
💡 Suggestion — #nullable disable inconsistency in new file
All sibling files in Platform/Windows/CollectionView/ have #nullable disable at the top (GroupFooterItemTemplateContext.cs, GroupedItemTemplateCollection.cs, GroupTemplateContext.cs). The new GroupFooterDataTemplateSelector.cs omits it and instead uses nullable annotations (UWPDataTemplate?). This is actually the preferred modern approach, but mixing conventions within a directory can cause confusion. Either add #nullable disable for consistency or document the intent (opting in to nullable awareness).
💡 Suggestion — Test doesn't exercise the first CollectionView (no templates at all)
Issue23293.cs creates two CollectionViews: one with no templates, one with GroupHeaderTemplate + GroupFooterTemplate. The test only waits for "GroupFooterLabel" (from the second view) and then takes a screenshot. The first CollectionView (CollectionViewWithoutDataTemplate) — the simpler scenario where items should just display their ToString() — has no assertion. A WaitForElement("CollectionViewWithoutDataTemplate") followed by a label-text assertion for "American Black Bear" would close the loop on the full issue scenario.
Devil's Advocate
On warning #1 (null template): The ItemsViewDefaultTemplate is defined in ItemsViewStyles.xaml which is a merged dictionary baked into the MAUI WinUI assembly. It will always be present when the handler is live. The concern is theoretical. I'm not withdrawing it — defensive code costs nothing here — but I wouldn't block a ship on it.
On warning #2 (dynamic scenario): Before this PR, GroupFooterTemplate with ItemTemplate=null was already completely broken on Windows. This PR fixes the static case without making the dynamic case worse. The dynamic gap is real but arguably out of scope for an issue-specific fix, and the existing mapper architecture (calling UpdateItemsSource rather than UpdateItemTemplate) is a separate structural question. The warning is valid but soft.
On the approach: Passing raw items to skip TemplatedItemSourceFactory is clean and doesn't regress grouped views that have an ItemTemplate (the old code path is preserved). The GroupTemplateContext mutation of the raw list (appending the fake footer item) is the existing design — this PR works correctly within that contract.
Verdict: NEEDS_CHANGES
Confidence: medium
Summary: The core fix is architecturally sound and correctly addresses the reported static-configuration bug on Windows. The two _footerTemplate and the unhandled dynamic GroupFooterTemplate update path — should be addressed before merge: the null guard is a one-liner, and the dynamic gap should either be fixed or explicitly documented as a known limitation. The CI maui-pr failure also needs confirmation that the Helix cancellations are infrastructure-related and not caused by the PR.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | Synthetic DataTemplate + uniform ItemTemplateContext wrapping; MapIsGrouped calls UpdateItemTemplate; eliminates GroupFooterDataTemplateSelector | ✅ PASS | 2 files | Fixes dynamic update gap; no null-guard risk; trim-safe via BindingContextChanged |
| 2 | try-fix (claude-sonnet-4.6) | Fix-What's-Already-There: null-guard on _footerTemplate, add MapGroupFooterTemplate calling UpdateItemTemplate(), commit missing Windows snapshot | ✅ PASS | 5 files + snapshot | Minimal surgical patch to PR's existing approach; addresses both code review warnings |
| 3 | try-fix (gpt-5.3-codex) | DefaultStringItemTemplateContext — override ToString() on wrapper to show raw data; no selector | ❌ FAIL | 1 file | Fixes item stringification but footer template not applied when ItemTemplate=null |
| 4 | try-fix (gpt-5.4) | DisplayMemberPath="Item" approach — keep wrapped items, set DisplayMemberPath | ❌ FAIL | 2 files | App closed while waiting for GroupFooterLabel |
| 5 | try-fix (gpt-5.3-codex) | Per-container footer templating in PrepareContainerForItemOverride; raw items in GroupedItemTemplateCollection | ❌ FAIL | 4 files | App window location failure during test |
| PR | PR #28617 | Raw items list in GroupedItemTemplateCollection + GroupFooterDataTemplateSelector for footer routing | ❌ FAIL (Gate — missing Windows snapshot) | 3 impl + 4 test files | Functionally working but snapshot missing; code review found 2 warnings |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | No | No new ideas |
| claude-sonnet-4.6 | 2 | No | No new ideas |
| gpt-5.3-codex | 2 | Yes | Per-container PrepareContainerForItemOverride footer templating → ran as attempt 5 (FAIL) |
| gpt-5.4 | 2 | Yes | Per-container PrepareContainerForItemOverride footer templating → ran as attempt 5 (FAIL) |
| claude-opus-4.6 | 3 | Yes | Fix in ItemContentControl.Realize() fallback — not run: broader blast radius than issue scope, max rounds reached |
| gpt-5.4 | 3 | Yes | Group footer via GroupStyle ContainerStyle/ControlTemplate — not run: complex GroupStyle redesign, max rounds reached |
Exhausted: Yes (max 3 rounds reached; 2 ideas from round 3 not run due to significantly broader blast radius than issue scope)
Selected Fix: Candidate #2 — Minimal surgical patch to PR's existing approach. Reasons:
- Simpler: preserves the PR's established raw-items + GroupFooterDataTemplateSelector design
- Addresses both code review
⚠️ warnings directly (null-guard + dynamic update path) - Adds the missing Windows snapshot
- Fewer architectural changes than Candidate 1 (no synthetic DataTemplate needed)
- Consistent with codebase conventions
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #23293 is Windows-only; PR adds GroupedItemTemplateCollection raw-items path + GroupFooterDataTemplateSelector + UI test |
| Code Review | NEEDS_CHANGES (medium) | 0 errors, 2 warnings, 3 suggestions |
| Gate | ❌ FAILED | Windows — element appears but Windows snapshot baseline not committed |
| Try-Fix | ✅ COMPLETE | 5 attempts, 2 passing; best alternative is Candidate #2 |
| Report | ✅ COMPLETE |
Code Review Impact on Try-Fix
The two code-review _footerTemplate and a MapGroupFooterTemplate that calls UpdateItemTemplate() to close the dynamic update gap. Attempt 1 took a more sweeping approach (eliminating GroupFooterDataTemplateSelector entirely via synthetic DataTemplate), which also removed both warning sites. Attempts 3–5 tried progressively different data-layer and rendering-layer strategies, all failing to produce a passing test while addressing both warnings — reinforcing Candidate 2 as the right path.
Summary
The PR fixes a real Windows-only bug: grouped CollectionView with no ItemTemplate displayed the class name of ItemTemplateContext wrappers instead of the raw data's ToString(). The core fix — exposing raw group items in GroupedItemTemplateCollection and using GroupFooterDataTemplateSelector to route footer items — is architecturally correct and is confirmed working by the gate (the element appears; the test fails only on the missing Windows snapshot baseline).
Three issues prevent this PR from being merged as-is:
- Missing Windows snapshot — the gate fails because
GroupedCollectionViewWithoutItemTemplateRendersCorrectly.pngfor Windows was never committed (only iOS and Android baselines exist). - Null guard missing —
GroupFooterDataTemplateSelector._footerTemplateuses_footerTemplate!without verifying the resource exists, which would silently reproduce the original bug without a diagnostic. - Dynamic update gap — setting
GroupFooterTemplateafter initial layout does not triggerUpdateItemTemplate(), so theItemTemplateSelectoris never installed for this scenario.
Candidate #2 (Attempt 2) addresses all three issues with a minimal surgical patch: null-guard, MapGroupFooterTemplate calling UpdateItemTemplate(), and the missing Windows snapshot. This is the recommended path forward.
Root Cause
On Windows, when ItemTemplate is not set, TemplatedItemSourceFactory.Create() wraps each group item in an ItemTemplateContext. WinUI's ListViewBase then calls ToString() on the ItemTemplateContext wrapper (showing the class name) rather than on the underlying data object. The fix passes raw data objects directly into the group items list so WinUI calls ToString() on the actual data, while GroupFooterDataTemplateSelector ensures the fake footer item (GroupFooterItemTemplateContext) still gets routed through ItemsViewDefaultTemplate for proper footer rendering.
Fix Quality
The PR's fix direction is correct but incomplete. It needs three changes before merge:
- Commit the Windows snapshot baseline
- Add null-guard on
_footerTemplatewith aDebug.Faildiagnostic - Add
MapGroupFooterTemplate(Windows-only) calling bothUpdateItemsSource()andUpdateItemTemplate()
Candidate #2 delivers all three in a minimal patch. The PR should be updated with these changes rather than replaced wholesale.
📋 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 review the ai's summary?

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