Skip to content

[Windows] Fixed CollectionView throws NRE when value of IsGrouped property is changed to false#27331

Merged
kubaflo merged 8 commits intodotnet:inflight/currentfrom
NirmalKumarYuvaraj:fix-17864
Mar 24, 2026
Merged

[Windows] Fixed CollectionView throws NRE when value of IsGrouped property is changed to false#27331
kubaflo merged 8 commits intodotnet:inflight/currentfrom
NirmalKumarYuvaraj:fix-17864

Conversation

@NirmalKumarYuvaraj
Copy link
Copy Markdown
Contributor

@NirmalKumarYuvaraj NirmalKumarYuvaraj commented Jan 24, 2025

Issue Details

NullReference exception is thrown when disabling IsGrouped at runtime.

Root Cause

The value passed as the itemsource when creating a groupItemsList is not IEnumerable. This causes the value to be set as null.

Description of Change

Ensured the value is of type IEnumerable and pass it to Create method of TemplatedItemSourceFactory to avoid null reference exceptions.

Validated the behaviour in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Issues Fixed

Fixes #17864
Fixes #28824

Output

Before After
Before.mp4
After.mp4

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Jan 24, 2025
@karthikraja-arumugam karthikraja-arumugam added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jan 24, 2025
@NirmalKumarYuvaraj NirmalKumarYuvaraj marked this pull request as ready for review January 27, 2025 10:27
Copilot AI review requested due to automatic review settings January 27, 2025 10:27
@NirmalKumarYuvaraj NirmalKumarYuvaraj requested a review from a team as a code owner January 27, 2025 10:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml: Language not supported
Comments suppressed due to low confidence (1)

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue17864.cs:22

  • Add a check to ensure that the CollectionView is correctly updated after the IsGrouped property changes.
App.WaitForElement(CollectionView);

public void CollectionViewShouldNotCrashWhenIsGroupedChanges()
{
App.WaitForElement(CollectionView);
App.Tap("Button");
Copy link

Copilot AI Jan 27, 2025

Choose a reason for hiding this comment

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

Ensure that the AutomationId for 'Button' is unique and not reused, or WaitForElement will fail to find the correct element.

Copilot uses AI. Check for mistakes.
@jsuarezruiz
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@jsuarezruiz
Copy link
Copy Markdown
Contributor

jsuarezruiz commented Feb 26, 2025

/rebase

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

@jfversluis jfversluis added the area-controls-collectionview CollectionView, CarouselView, IndicatorView label Mar 25, 2025
@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

jfversluis and others added 2 commits March 20, 2026 09:54
## Description

Remove the "Are you waiting for the changes in this PR to be merged?"
note from all Copilot instruction files.

This note was previously required at the top of every PR description so
users could find instructions on how to test PR artifacts. We now have a
**dogfooding comment bot** that automatically posts testing instructions
under each PR, making this manual note redundant.

Copilot agents were still prepending this note to every PR description
because it was hardcoded in:
- `.github/copilot-instructions.md` (main instructions)
- `.github/skills/pr-finalize/SKILL.md` (PR finalization skill)
- `.github/skills/pr-finalize/references/complete-example.md` (example
PR)

### Issues Fixed

N/A — instruction cleanup only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Problem

The `maui-pr-uitests` pipeline has 98+ test jobs that all publish
artifacts using `PublishBuildArtifacts@1` with **no artifact name**,
defaulting to `drop`. When multiple jobs upload the same file to the
same container simultaneously, AzDO blob storage encounters write
conflicts:

```
Blob is incomplete (missing block). Blob: 29adda685a1ff1119a49000d3a9183a5, Expected Offset: 0, Actual Offset: 8388608
##[error]File upload failed even after retry.
```

### Recent failures
- [Build
1334980](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1334980):
3 jobs failed (Controls CollectionView, Controls (vlatest), Controls
(vlatest) CollectionView)
- [Build
1334245](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1334245):
1 job failed (Controls (vlatest))

The specific collision: both "Controls (vlatest)" and "Controls
(vlatest) CollectionView" upload
`drop/logs/appium_ios_Controls.TestCases.iOS.Tests-Release-ios-CollectionView.log`
— same blob ID, concurrent writes.

## Fix

Add a unique artifact name per job using
`$(System.StageName)-$(System.JobName)-$(System.JobAttempt)` in
`eng/pipelines/common/ui-tests-steps.yml`. This matches the pattern
already used by snapshot diff artifacts in
`ui-tests-collect-snapshot-diffs.yml`.

Fixes dotnet#34477
Ref: dotnet/dnceng#1916

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 22, 2026

🤖 AI Summary

📊 Expand Full Review50c4abc · Addressed AI summary concern
🔍 Pre-Flight — Context & Validation

Issue: #17864 - [Windows] CollectionView throws NRE when value of IsGrouped property is changed to false
Related Issue: #28824 - [Windows] NullReferenceException thrown When Toggling IsGrouped to True in ObservableCollection Binding
PR: #27331 - [Windows] Fixed CollectionView throws NRE when value of IsGrouped property is changed to false
Platforms Affected: Windows
Files Changed: 1 implementation, 3 test
Test Type: UI test (TestCases.HostApp + TestCases.Shared.Tests)

Key Findings

  • The PR changes only src/Controls/src/Core/Platform/Windows/CollectionView/GroupedItemTemplateCollection.cs, making grouped item source creation conditional on the group object implementing IEnumerable.
  • Added coverage is a HostApp issue page plus a UI test for Issue17864; the test exercises toggling IsGrouped from true to false and verifies the app does not crash.
  • The PR description claims to fix both #17864 and #28824, but the added test coverage appears targeted only at #17864.
  • Issue #17864 was verified on Windows and explicitly reported as not reproducing on Android; issue #28824 reports the opposite toggle direction (false to true) on Windows.
  • Existing PR discussion contains one low-signal Copilot review comment about AutomationId uniqueness; no prior agent review summary was found to import.

Edge Cases Mentioned in Context

  • #17864: toggling from grouped data to flat data while IsGrouped becomes false.
  • #28824: toggling from flat data to grouped mode while still bound to a flat ObservableCollection/List.
  • Prior verification comments indicate Windows is the affected platform; Android was explicitly called out as not repro for #17864.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #27331 Guard grouped item source creation so TemplatedItemSourceFactory.Create(...) is only called when the group object implements IEnumerable. PENDING (Gate) src/Controls/src/Core/Platform/Windows/CollectionView/GroupedItemTemplateCollection.cs, src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml, src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml.cs, src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue17864.cs PR claims #17864 and #28824; explicit added UI test appears to cover only #17864.

Issue: #17864 - [Windows] CollectionView throws NRE when value of IsGrouped property is changed to false
Related Issue: #28824 - [Windows] NullReferenceException thrown When Toggling IsGrouped to True in ObservableCollection Binding
PR: #27331 - [Windows] Fixed CollectionView throws NRE when value of IsGrouped property is changed to false
Platforms Affected: Windows
Files Changed: 1 implementation, 3 test
Test Type: UI test (TestCases.HostApp + TestCases.Shared.Tests)

Key Findings

  • The live review branch currently changes src/Controls/src/Core/Platform/Windows/CollectionView/TemplatedItemSourceFactory.cs, not GroupedItemTemplateCollection.cs; it returns Array.Empty<object>() when Create(...) receives a null itemsSource.
  • Added coverage includes a HostApp issue page plus a UI test for Issue17864; the test exercises both true -> false and false -> true while items remain flat transitions.
  • Issue [Windows] CollectionView throws NRE when value of IsGrouped property is changed to false #17864 is explicitly Windows-only and was reported as not reproducing on Android; issue [Windows] NullReferenceException thrown When Toggling IsGrouped to True in ObservableCollection Binding #28824 is a related Windows repro for the opposite toggle direction.
  • Prior PR discussion includes an older AI review summary and a low-signal Copilot comment about AutomationId uniqueness, but the author later stated those concerns were addressed and the current branch diff reflects a different implementation.
  • The PR description still claims validation on Android, Windows, iOS, and Mac even though the issue context and added automated coverage are Windows-focused.

Edge Cases Mentioned in Context

  • #17864: toggling from grouped data to flat data while IsGrouped becomes false.
  • #28824: toggling from flat data to grouped mode while the bound items remain a flat ObservableCollection/List.
  • The new UI repro page intentionally exercises both toggle directions on Windows.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #27331 Normalize null grouped item sources at the Windows templated-item factory boundary by returning Array.Empty<object>() from TemplatedItemSourceFactory.Create(...). PENDING (Gate) src/Controls/src/Core/Platform/Windows/CollectionView/TemplatedItemSourceFactory.cs, src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml, src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml.cs, src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue17864.cs Current branch content differs from an earlier AI summary comment on the PR; gate should validate the live implementation.

🚦 Gate — Test Verification

Gate Result: PASSED

Platform: windows
Mode: Full Verification

  • Tests FAIL without fix:
  • Tests PASS with fix:

Evidence Summary: Issue17864 failed without the fix (app crash / expected failure) and passed with the fix restored on Windows. Full verification report was generated under CustomAgentLogsTmp/PRState/27331/PRAgent/gate/verify-tests-fail/verification-report.md.


Gate Result: PASSED

Platform: windows
Mode: Full Verification

  • Tests FAIL without fix:
  • Tests PASS with fix:

Evidence Summary: Issue17864 failed without the fix (app crash / expected failure) and passed with the fix restored on Windows. Full verification report was generated under CustomAgentLogsTmp/PRState/27331/PRAgent/gate/verify-tests-fail/verification-report.md.


🔧 Fix — Analysis & Comparison

Gate Result: PASSED

Platform: windows
Mode: Full Verification

  • Tests FAIL without fix:
  • Tests PASS with fix:

Evidence Summary: Issue17864 failed without the fix (app crash / expected failure) and passed with the fix restored on Windows. Full verification report was generated under CustomAgentLogsTmp/PRState/27331/PRAgent/gate/verify-tests-fail/verification-report.md.


Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) Guard grouped source creation upstream in GroupedItemTemplateCollection and harden GroupTemplateContext against non-IEnumerable items. PASS 2 files Avoids propagating null grouped items and closes the footer path too.
2 try-fix (claude-sonnet-4.6) Guard ItemTemplateContextEnumerable.GetEnumerator() so a null _itemsSource yields an empty enumeration. PASS 1 file Smallest leaf-level fix; handles the exact crash site directly.
3 try-fix (gpt-5.3-codex) Normalize null input in the ItemTemplateContextEnumerable constructor so the instance always wraps an empty enumerable instead of null. PASS 1 file Similar to candidate #2, but normalizes earlier in object lifetime.
4 try-fix (gemini-3-pro-preview) Coalesce null source in TemplatedItemSourceFactory.Create when constructing ItemTemplateContextEnumerable, preserving the wrapper type instead of returning a raw array. PASS 1 file Closest alternative to the PR fix; keeps the wrapper alive.
5 try-fix (claude-opus-4.6, round 2 idea) Normalize invalid groups before they enter the factory and harden GroupTemplateContext as a safety net. PASS 2 files Functionally close to candidate #1; not meaningfully better than the PR fix.
6 try-fix (claude-sonnet-4.6, round 2 idea) Treat invalid top-level groups as singleton groups instead of empty ones. PASS 1 file Prevents the crash but changes semantics by showing stray items as one-item groups.
7 try-fix (gpt-5.3-codex, round 2 idea) Clear the native Windows handler items source during IsGrouped transitions before rebuilding. FAIL 1 file Did not stop the crash; timing-layer reset was too late to prevent bad grouped data reaching the pipeline.
8 try-fix (gemini-3-pro-preview, round 2 idea) Defer grouped source rebuild in the Windows handler until state changes settle. FAIL 1 file Repeated retries still crashed; scheduling later did not fix the bad grouped shape.
9 try-fix (claude-opus-4.6, round 3 idea) Add a group-shape gate in GroupedItemTemplateCollection and skip non-enumerable top-level items during grouped rebuilds. PASS 1 file Semantically precise, but more invasive because grouped collection update paths need null filtering.
10 try-fix (claude-sonnet-4.6, round 3 idea) Revisited null-safety lower in the pipeline and converged on the same enumerator guard as candidate #2. PASS 1 file Duplicate of candidate #2 rather than a distinct new fix.
11 try-fix (gemini-3-pro-preview, round 3 idea) Coalesce non-IEnumerable groups to Array.Empty<object>() at the GroupedItemTemplateCollection call site. PASS 1 file Valid caller-side guard, but conceptually similar to the PR's boundary normalization.
PR PR #27331 Normalize null grouped item sources at the Windows templated-item factory boundary by returning Array.Empty<object>() from TemplatedItemSourceFactory.Create(...). PASSED (Gate) 4 files Original PR; gate passed on Windows and covers both toggle directions via Issue17864.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 Yes Normalize invalid group objects at the group-context layer before the factory sees them.
claude-sonnet-4.6 2 Yes Treat invalid top-level groups as singleton groups rather than null/empty.
gpt-5.3-codex 2 Yes Clear native ItemsSource during grouped/un-grouped transitions at the Windows handler layer.
gemini-3-pro-preview 2 Yes Defer grouped source rebuild in the Windows handler until property changes settle.
claude-opus-4.6 3 Yes Skip grouped rebuild for invalid top-level groups instead of normalizing them.
claude-sonnet-4.6 3 Yes Add null-safe accessors lower in the item-template pipeline (which converged to candidate #2).
gpt-5.3-codex 3 No NO NEW IDEAS
gemini-3-pro-preview 3 Yes Guard the async-dispatch/disposal gap in grouped change handling (did not produce a distinct passing fix).

Exhausted: Yes max 3 rounds reached, and remaining ideas either duplicated already-tested null-normalization strategies or failed at the handler/timing layer.
Selected Fix: PR #27331 it is the best tradeoff because it applies the normalization once at the shared factory boundary, prevents null from reaching downstream grouped consumers, preserves empty-group semantics, and is less invasive than group-shape filtering while more robust than handler timing changes.


📋 Report — Final Recommendation

Gate Result: PASSED

Platform: windows
Mode: Full Verification

  • Tests FAIL without fix:
  • Tests PASS with fix:

Evidence Summary: Issue17864 failed without the fix (app crash / expected failure) and passed with the fix restored on Windows. Full verification report was generated under CustomAgentLogsTmp/PRState/27331/PRAgent/gate/verify-tests-fail/verification-report.md.


Final Recommendation: APPROVE

Phase Status

Phase Status Notes
Pre-Flight COMPLETE Windows CollectionView fix with HostApp + shared UI coverage for Issue17864; current branch implements a factory-boundary null guard.
Gate PASSED Full Windows verification: test failed without fix and passed with fix.
Try-Fix COMPLETE 11 attempts run, 9 passing; handler-timing alternatives failed, and the PR's fix was selected as best.
Report COMPLETE

Summary

The PR should be approved. The live implementation is a small, robust Windows-only fix that passed gate verification and held up well against extensive try-fix exploration. The added repro page and UI test cover both toggle directions exercised by the bug scenario, so the review now has both regression coverage and empirical validation.

Root Cause

During Windows CollectionView IsGrouped transitions, a flat top-level item can temporarily flow through the grouped pipeline. GroupedItemTemplateCollection casts that item with group as IEnumerable; for flat items the cast yields null. Without normalization, that null reaches the templated-item pipeline and is later dereferenced while WinUI enumerates grouped items, producing the NullReferenceException.

Fix Quality

Multi-model try-fix found many passing variants, but they all clustered around the same core idea: normalize or reject invalid grouped input somewhere in the data pipeline. The two handler-layer timing ideas failed. Among the passing candidates, the PR's factory-boundary normalization is the best balance of simplicity and robustness: it is smaller and less invasive than group-shape gating, avoids the semantic change introduced by singleton wrapping, and prevents null from leaking to downstream grouped consumers earlier than leaf-level enumerator guards.


@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR labels Mar 22, 2026
@MauiBot MauiBot added the s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) label Mar 22, 2026
Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

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

Could you please review the AI's summary?

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 23, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 27331

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 27331"

@NirmalKumarYuvaraj
Copy link
Copy Markdown
Contributor Author

@kubaflo , Addressed AI review summary concerns.

@MauiBot MauiBot added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR labels Mar 24, 2026
@kubaflo kubaflo added the s/agent-fix-implemented PR author implemented the agent suggested fix label Mar 24, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current March 24, 2026 12:55
@kubaflo kubaflo merged commit ba42322 into dotnet:inflight/current Mar 24, 2026
28 of 31 checks passed
PureWeen pushed a commit that referenced this pull request Mar 24, 2026
…perty is changed to false (#27331)

### Issue Details

NullReference exception is thrown when disabling IsGrouped at runtime.

### Root Cause

The value passed as the itemsource when creating a groupItemsList is not
IEnumerable. This causes the value to be set as null.

### Description of Change

Ensured the value is of type IEnumerable and pass it to Create method of
TemplatedItemSourceFactory to avoid null reference exceptions.

Validated the behaviour in the following platforms

- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Issues Fixed

Fixes #17864
Fixes #28824

### Output

| Before | After |
| ------ | ----- |
|<video
src="https://github.com/user-attachments/assets/a651b7ce-a1e7-4603-95bc-9638fc3cf7c7">|<video
src="https://github.com/user-attachments/assets/3729a956-d37e-4fc2-aaa2-ec4c43493054">|

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-implemented PR author implemented the agent suggested fix s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

8 participants