Skip to content

[iOS] Fixed issue where group Header/Footer template was set to all items when IsGrouped was true for an ObservableCollection - #29144

Merged
kubaflo merged 8 commits into
dotnet:inflight/currentfrom
Tamilarasan-Paranthaman:fix-29141
Mar 5, 2026
Merged

kubaflo merged 8 commits into
dotnet:inflight/currentfrom
Tamilarasan-Paranthaman:fix-29141

Conversation

@Tamilarasan-Paranthaman

@Tamilarasan-Paranthaman Tamilarasan-Paranthaman commented Apr 23, 2025 •

Copy link
Copy Markdown
Member

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 1: Group header and footer templates not updating correctly at runtime on iOS.

Root Cause

The mapper for GroupFooterTemplateProperty and GroupHeaderTemplateProperty in GroupableItemsViewHandler was conditionally compiled with #if WINDOWS || __ANDROID__ || TIZEN, meaning it was excluded from iOS builds. As a result, changing the template at runtime on iOS had no effect and templates were never displayed.

Description of Change

Removed the #if WINDOWS || __ANDROID__ || TIZEN preprocessor guard from GroupableItemsViewHandler.cs, making the GroupFooterTemplateProperty and GroupHeaderTemplateProperty mappers active on all platforms including iOS. Both mappers call MapIsGrouped, which triggers UpdateItemsSource() and refreshes the grouping state.


Issue 2: Group header/footer templates incorrectly applied to all items in a flat ObservableCollection when IsGrouped = true.

Root Cause

In ObservableGroupedSource.cs (iOS), the GroupsCount() method iterated over all items in _groupSource and counted every item, regardless of whether it was an IEnumerable (i.e., an actual group). When IsGrouped = true but the source was a flat ObservableCollection<T> (non-grouped), each non-grouped item was counted as a section, causing NumberOfSections to be inflated. This led to header and footer templates being incorrectly applied to every item.

Description of Change

Modified GroupsCount() to only increment the count for items that implement IEnumerable. Non-IEnumerable items are no longer counted as sections. As a result, NumberOfSections now correctly reflects the number of actual groups, preventing header/footer templates from appearing for non-grouped items.


Issues Fixed

Fixes #29141

Test Case

Tests for this fix are included in this PR:

  • src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs — HostApp page with a CollectionView bound to a flat ObservableCollection, with radio buttons to toggle IsGrouped, GroupHeaderTemplate, and GroupFooterTemplate at runtime.
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs — NUnit UI test verifying that group header/footer template views are NOT shown when the source collection is not grouped.

Note: The test is currently excluded from Windows (unrelated NullReferenceException — see #28824) and Android (separate fix in PR #28886). It runs on iOS and MacCatalyst.

Platforms Tested

  • iOS
  • Android
  • Mac
  • Windows

@dotnet-policy-service dotnet-policy-service Bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Apr 23, 2025
@jsuarezruiz jsuarezruiz added platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Apr 23, 2025
@Tamilarasan-Paranthaman
Tamilarasan-Paranthaman marked this pull request as ready for review April 25, 2025 12:22
Copilot AI review requested due to automatic review settings April 25, 2025 12:22
@Tamilarasan-Paranthaman
Tamilarasan-Paranthaman requested a review from a team as a code owner April 25, 2025 12:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes the issue where group header and footer templates were incorrectly applied and not updating as expected when the ObservableCollection’s IsGrouped property was true.

  • Adds group header/footer template mappings for iOS in CollectionViewHandler2.iOS.cs.
  • Updates ObservableGroupedSource.cs to only add groups that implement IEnumerable.
  • Removes platform-specific mapping conditions in GroupableItemsViewHandler.cs.

Reviewed Changes

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

File Description
src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs Adds new mapping for group header/footer templates to support dynamic updates on iOS.
src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs Adjusts group source creation with a type-check to include only IEnumerable groups.
src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.cs Removes conditional mapping for group header/footer templates on certain platforms.

Comment thread src/Controls/src/Core/Handlers/Items/iOS/ObservableGroupedSource.cs Outdated
@jsuarezruiz

Copy link
Copy Markdown
Contributor

/azp run MAUI-UITests-public

@azure-pipelines

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

@jsuarezruiz jsuarezruiz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There are some related tests failing on iOS and Mac:
image
Could you review if are related with the changes?

@Tamilarasan-Paranthaman

Copy link
Copy Markdown
Member Author

There are some related tests failing on iOS and Mac: image Could you review if are related with the changes?

@jsuarezruiz , yes, the failures were caused by these changes. I have updated the fix and committed the changes. Could you please review them and let me know if you have any concerns?

@jsuarezruiz

Copy link
Copy Markdown
Contributor

/azp run MAUI-UITests-public

@azure-pipelines

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

@PureWeen PureWeen added this to the .NET 9 SR9 milestone Jun 10, 2025
@PureWeen PureWeen added the p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint label Jun 10, 2025
@PureWeen PureWeen moved this from Todo to Approved in MAUI SDK Ongoing Jun 10, 2025
@PureWeen PureWeen moved this from Approved to Ready To Review in MAUI SDK Ongoing Jun 10, 2025
@PureWeen PureWeen modified the milestones: .NET 9 SR9, .NET 9 SR10 Jul 3, 2025
@PureWeen PureWeen modified the milestones: .NET 9 SR10, .NET 9 SR11 Aug 4, 2025
@PureWeen PureWeen modified the milestones: .NET 9 SR11, .NET 10 SR1 Sep 10, 2025
@PureWeen PureWeen modified the milestones: .NET 10 SR1, .NET 10.0 SR2 Nov 4, 2025
@Vignesh-SF3580

Copy link
Copy Markdown
Contributor

Could you please verify #29144 (comment)

@kubaflo Based on the AI summary, I implemented the recommended improvements using a try-fix approach. Also, I added test cases to cover the suggested edge cases and applied these improvements to Android as well.

@kubaflo kubaflo added s/agent-fix-implemented PR author implemented the agent suggested fix s/agent-fix-win AI found a better alternative fix than the PR 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 4, 2026
@github-project-automation github-project-automation Bot moved this from Changes Requested to Approved in MAUI SDK Ongoing Mar 5, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current March 5, 2026 12:53
@kubaflo
kubaflo merged commit f67ab7f into dotnet:inflight/current Mar 5, 2026
29 checks passed
@github-project-automation github-project-automation Bot moved this from Approved to Done in MAUI SDK Ongoing Mar 5, 2026
PureWeen added a commit that referenced this pull request Mar 11, 2026
…tems when IsGrouped was true for an ObservableCollection (#29144)

<!-- 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!

## Issue 1: Group header and footer templates not updating correctly at
runtime on iOS.

### Root Cause

The mapper for `GroupFooterTemplateProperty` and
`GroupHeaderTemplateProperty` in `GroupableItemsViewHandler` was
conditionally compiled with `#if WINDOWS || __ANDROID__ || TIZEN`,
meaning it was excluded from iOS builds. As a result, changing the
template at runtime on iOS had no effect and templates were never
displayed.

### Description of Change

Removed the `#if WINDOWS || __ANDROID__ || TIZEN` preprocessor guard
from `GroupableItemsViewHandler.cs`, making the
`GroupFooterTemplateProperty` and `GroupHeaderTemplateProperty` mappers
active on all platforms including iOS. Both mappers call `MapIsGrouped`,
which triggers `UpdateItemsSource()` and refreshes the grouping state.

---

## Issue 2: Group header/footer templates incorrectly applied to all
items in a flat ObservableCollection when `IsGrouped = true`.

### Root Cause

In `ObservableGroupedSource.cs` (iOS), the `GroupsCount()` method
iterated over all items in `_groupSource` and counted every item,
regardless of whether it was an `IEnumerable` (i.e., an actual group).
When `IsGrouped = true` but the source was a flat
`ObservableCollection<T>` (non-grouped), each non-grouped item was
counted as a section, causing `NumberOfSections` to be inflated. This
led to header and footer templates being incorrectly applied to every
item.

### Description of Change

Modified `GroupsCount()` to only increment the count for items that
implement `IEnumerable`. Non-`IEnumerable` items are no longer counted
as sections. As a result, `NumberOfSections` now correctly reflects the
number of actual groups, preventing header/footer templates from
appearing for non-grouped items.

---

### Issues Fixed

Fixes #29141

### Test Case

Tests for this fix are included in this PR:
- `src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs` — HostApp
page with a `CollectionView` bound to a flat `ObservableCollection`,
with radio buttons to toggle `IsGrouped`, `GroupHeaderTemplate`, and
`GroupFooterTemplate` at runtime.
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs`
— NUnit UI test verifying that group header/footer template views are
NOT shown when the source collection is not grouped.

> **Note:** The test is currently excluded from Windows (unrelated
NullReferenceException — see #28824) and Android (separate fix in PR
#28886). It runs on iOS and MacCatalyst.

### Platforms Tested

- [x] iOS
- [x] Android
- [x] Mac
- [ ] Windows
</details>

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
github-actions Bot added a commit that referenced this pull request Mar 11, 2026
…tems when IsGrouped was true for an ObservableCollection (#29144)

<!-- 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!

## Issue 1: Group header and footer templates not updating correctly at
runtime on iOS.

### Root Cause

The mapper for `GroupFooterTemplateProperty` and
`GroupHeaderTemplateProperty` in `GroupableItemsViewHandler` was
conditionally compiled with `#if WINDOWS || __ANDROID__ || TIZEN`,
meaning it was excluded from iOS builds. As a result, changing the
template at runtime on iOS had no effect and templates were never
displayed.

### Description of Change

Removed the `#if WINDOWS || __ANDROID__ || TIZEN` preprocessor guard
from `GroupableItemsViewHandler.cs`, making the
`GroupFooterTemplateProperty` and `GroupHeaderTemplateProperty` mappers
active on all platforms including iOS. Both mappers call `MapIsGrouped`,
which triggers `UpdateItemsSource()` and refreshes the grouping state.

---

## Issue 2: Group header/footer templates incorrectly applied to all
items in a flat ObservableCollection when `IsGrouped = true`.

### Root Cause

In `ObservableGroupedSource.cs` (iOS), the `GroupsCount()` method
iterated over all items in `_groupSource` and counted every item,
regardless of whether it was an `IEnumerable` (i.e., an actual group).
When `IsGrouped = true` but the source was a flat
`ObservableCollection<T>` (non-grouped), each non-grouped item was
counted as a section, causing `NumberOfSections` to be inflated. This
led to header and footer templates being incorrectly applied to every
item.

### Description of Change

Modified `GroupsCount()` to only increment the count for items that
implement `IEnumerable`. Non-`IEnumerable` items are no longer counted
as sections. As a result, `NumberOfSections` now correctly reflects the
number of actual groups, preventing header/footer templates from
appearing for non-grouped items.

---

### Issues Fixed

Fixes #29141

### Test Case

Tests for this fix are included in this PR:
- `src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs` — HostApp
page with a `CollectionView` bound to a flat `ObservableCollection`,
with radio buttons to toggle `IsGrouped`, `GroupHeaderTemplate`, and
`GroupFooterTemplate` at runtime.
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs`
— NUnit UI test verifying that group header/footer template views are
NOT shown when the source collection is not grouped.

> **Note:** The test is currently excluded from Windows (unrelated
NullReferenceException — see #28824) and Android (separate fix in PR
#28886). It runs on iOS and MacCatalyst.

### Platforms Tested

- [x] iOS
- [x] Android
- [x] Mac
- [ ] Windows
</details>

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
@PureWeen PureWeen mentioned this pull request Mar 17, 2026
PureWeen added a commit that referenced this pull request Mar 19, 2026
…tems when IsGrouped was true for an ObservableCollection (#29144)

<!-- 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!

## Issue 1: Group header and footer templates not updating correctly at
runtime on iOS.

### Root Cause

The mapper for `GroupFooterTemplateProperty` and
`GroupHeaderTemplateProperty` in `GroupableItemsViewHandler` was
conditionally compiled with `#if WINDOWS || __ANDROID__ || TIZEN`,
meaning it was excluded from iOS builds. As a result, changing the
template at runtime on iOS had no effect and templates were never
displayed.

### Description of Change

Removed the `#if WINDOWS || __ANDROID__ || TIZEN` preprocessor guard
from `GroupableItemsViewHandler.cs`, making the
`GroupFooterTemplateProperty` and `GroupHeaderTemplateProperty` mappers
active on all platforms including iOS. Both mappers call `MapIsGrouped`,
which triggers `UpdateItemsSource()` and refreshes the grouping state.

---

## Issue 2: Group header/footer templates incorrectly applied to all
items in a flat ObservableCollection when `IsGrouped = true`.

### Root Cause

In `ObservableGroupedSource.cs` (iOS), the `GroupsCount()` method
iterated over all items in `_groupSource` and counted every item,
regardless of whether it was an `IEnumerable` (i.e., an actual group).
When `IsGrouped = true` but the source was a flat
`ObservableCollection<T>` (non-grouped), each non-grouped item was
counted as a section, causing `NumberOfSections` to be inflated. This
led to header and footer templates being incorrectly applied to every
item.

### Description of Change

Modified `GroupsCount()` to only increment the count for items that
implement `IEnumerable`. Non-`IEnumerable` items are no longer counted
as sections. As a result, `NumberOfSections` now correctly reflects the
number of actual groups, preventing header/footer templates from
appearing for non-grouped items.

---

### Issues Fixed

Fixes #29141

### Test Case

Tests for this fix are included in this PR:
- `src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs` — HostApp
page with a `CollectionView` bound to a flat `ObservableCollection`,
with radio buttons to toggle `IsGrouped`, `GroupHeaderTemplate`, and
`GroupFooterTemplate` at runtime.
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs`
— NUnit UI test verifying that group header/footer template views are
NOT shown when the source collection is not grouped.

> **Note:** The test is currently excluded from Windows (unrelated
NullReferenceException — see #28824) and Android (separate fix in PR
#28886). It runs on iOS and MacCatalyst.

### Platforms Tested

- [x] iOS
- [x] Android
- [x] Mac
- [ ] Windows
</details>

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
jfversluis pushed a commit that referenced this pull request Mar 20, 2026
### Root Cause of the issue



- The failing test: `SetVisibility(Visibility.Collapsed)` device test on
iOS.

  Why it fails: PR #28983's fix maps Visibility → MapIsRunning in
  ActivityIndicatorHandler, which bypasses the standard
ViewExtensions.UpdateVisibility path. The standard path calls Collapse()
to
add a CollapseConstraint (an NSLayoutConstraint that zeros the view's
size).
The PR's UpdateIsRunning only sets Hidden = true — it never calls
Collapse()
- Crash in the FeatureMatrix Navigation Page Scenario in the iOS 26
PR #34326 added an else block in UpdateBarTextColor() that explicitly
sets BackButtonAppearance = null, BackIndicatorImage = null, and
BackIndicatorTransitionMaskImage = null on the navigation bar when no
custom color is applied. On iOS versions before 26, assigning null to
these properties was treated as "use system defaults." On iOS 26, the
Liquid Glass rendering pipeline reads these properties during push/pop
navigation transitions and throws an exception when it encounters an
explicit null — it expects either an unset property or a valid object.
Since useCustomColor is false by default (no IconColor set), this
crashes on every standard page navigation.
- Setting ThumbTintList = null in the else block removes the tint
entirely, causing the thumb to appear white instead of the default blue,
because SwitchCompat does not re-resolve its theme colors once the tint
list is cleared.
- SetAdjustViewBounds(false) was being applied to all images regardless
of their Aspect value. When this property is false, Android’s ImageView
does not resize itself based on the image’s intrinsic aspect ratio and
instead expands to fill the available space. As a result, an Image
control with the default AspectFit setting ignored its height constraint
and overflowed its container, causing the image to appear taller than
expected in the screenshot test.(LoadAndVerifyGif, ThemeRelated feature
tests)
- PR #29144 changed the group-detection guard in ObservableGroupedSource
(iOS and Android) from is IEnumerable to is ICollection to prevent
strings (which implement IEnumerable<char>) from being treated as
groups.
While the intent was correct, the change was too broad. Custom group
types that implement only IEnumerable<T> were also excluded. As a
result, _groupCount became zero on iOS and _groups remained empty on
Android, causing grouped CollectionView rendering failures and
IndexOutOfRangeException during Add/Remove operations.
- StepperHandler.iOS.cs compiles for both iOS and Mac Catalyst. On Mac
Catalyst / macOS 26, OperatingSystem.IsIOS() and IsIOSVersionAtLeast(26)
both return true, and the screen is always landscape. As a result, the
20pt glass pill compensation was incorrectly applied, inflating
GetDesiredSize(1,1) to width = 21. (Native View Bounding Box is not
empty - device Test failures)
- In PR #33428, the WindowInsetsCompat.Builder block in
MauiWindowInsetListener.ApplyDefaultWindowInsets was simplified to
return insets; to standardize inset handling. This change was unrelated
to the actual fix for #33344, which only required passing the bottom
inset through as unconsumed.
As part of that refactor, top inset consumption was also removed,
changing the prior contract where the top inset was consumed when
appBarHasContent = true. While normal safe-area scenarios worked
correctly, transient layout states (e.g., temporary Height = 0 during
keyboard dismissal, rotation, animation, or dynamic item generation)
triggered a second inset dispatch. In those moments, the top inset
satisfied the overlap condition and was applied to content before
SafeAreaExtensions could normalize it, causing test failures. Bottom
insets did not regress because their overlap condition cannot be met in
the same transient state. (EntryScrollTest,
HorizontalStackLayout_Spacing_WithLandscape,
VerticalStackLayout_Spacing_WithLandscape and so on failures)

### Description of Change



- Handles the three Visibility cases the same way as
ViewExtensions.UpdateVisibility:

`Visible`: Calls Inflate() (restores layout size) and sets Hidden =
false — identical to UpdateVisibility. Additionally starts/stops the
animation based on IsRunning.
`Hidden`: Calls Inflate() (preserves layout space) and sets Hidden =
true — identical to UpdateVisibility. The indicator keeps its layout
footprint but is invisible.
`Collapsed`: Sets Hidden = true and calls Collapse() (zeros out layout
size via constraints) — identical to UpdateVisibility. The indicator is
both invisible and takes up no space.
- Removed the else block entirely. When no custom color is applied,
these properties should remain untouched. The system defaults work
correctly on their own — there is no need to explicitly reset them to
null
- Removed the else block from UpdateThumbColor in SwitchExtensions.cs.
The default thumb color is managed by SwitchCompat internally from the
Material theme, so no explicit reset is needed.
- Restored the correct logic in ImageViewExtensions.UpdateAspect to call
SetAdjustViewBounds based on the image’s Aspect value:
- The guard has been updated from is ICollection to is IEnumerable &&
not string in the ObservableGroupedSource implementations for both iOS
and Android (GroupsCount(), UpdateGroupTracking(), Add(), Remove()).
This change specifically excludes string while allowing legitimate
custom group types that implement only IEnumerable<T>. The fix restores
the behavior for Issue22320 while keeping all Issue29141 scenarios
working correctly.
-Added !OperatingSystem.IsMacCatalyst() to the guard condition in
GetDesiredSize, restricting the 20pt compensation to real iOS 26+ only —
as intended in the original PR comment.
- Restored the original behavior by consuming the top inset when
appBarHasContent = true, while continuing to pass the bottom inset
through unconsumed (the only change required for #33344). This retains
the Android edge-to-edge fix and restores deterministic safe-area
handling.

### Testing related description of change
EditorNoOverlapAfterRotateToLandscape,
EditorNoOverlapAfterRotateToPortrait,
EntryFocusedShouldNotCauseGapAfterRotation Added cropLeft to remove the
navbar on Android and re-saved the image due to entry text changes in
this commit –
8d17a6d,
91047fb.

DrawStringShouldDrawText – The automation ID set to GraphicsView was not
found by Appium on the Windows platform, so a test condition was added
for Windows to take the image directly instead of waiting for the
GraphicsView.

Added the base images for iOS 26 and Mac that were not added previously.

Re-saved the images that failed due to the wrong iOS version image being
added in the PR.

Re-saved the test images that failed due to this fix PR:
#31254 — e.g.,
GraphicsViewFeatureTests and others.
 
Resaved the slider-related test images due to this fix PR —
#34064.

### Issues Fixed




Fixes #34437 



### Tested the behaviour in the following platforms



- [x] iOS
- [x] Mac

---------

Co-authored-by: SyedAbdulAzeem <syedabdulazeem.a@syncfusion.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
Co-authored-by: TamilarasanSF4853 <tamilarasan.velu@syncfusion.com>
Co-authored-by: LogishaSelvarajSF4525 <logisha.selvaraj@syncfusion.com>
github-actions Bot added a commit that referenced this pull request Mar 20, 2026
…tems when IsGrouped was true for an ObservableCollection (#29144)

<!-- 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!

## Issue 1: Group header and footer templates not updating correctly at
runtime on iOS.

### Root Cause

The mapper for `GroupFooterTemplateProperty` and
`GroupHeaderTemplateProperty` in `GroupableItemsViewHandler` was
conditionally compiled with `#if WINDOWS || __ANDROID__ || TIZEN`,
meaning it was excluded from iOS builds. As a result, changing the
template at runtime on iOS had no effect and templates were never
displayed.

### Description of Change

Removed the `#if WINDOWS || __ANDROID__ || TIZEN` preprocessor guard
from `GroupableItemsViewHandler.cs`, making the
`GroupFooterTemplateProperty` and `GroupHeaderTemplateProperty` mappers
active on all platforms including iOS. Both mappers call `MapIsGrouped`,
which triggers `UpdateItemsSource()` and refreshes the grouping state.

---

## Issue 2: Group header/footer templates incorrectly applied to all
items in a flat ObservableCollection when `IsGrouped = true`.

### Root Cause

In `ObservableGroupedSource.cs` (iOS), the `GroupsCount()` method
iterated over all items in `_groupSource` and counted every item,
regardless of whether it was an `IEnumerable` (i.e., an actual group).
When `IsGrouped = true` but the source was a flat
`ObservableCollection<T>` (non-grouped), each non-grouped item was
counted as a section, causing `NumberOfSections` to be inflated. This
led to header and footer templates being incorrectly applied to every
item.

### Description of Change

Modified `GroupsCount()` to only increment the count for items that
implement `IEnumerable`. Non-`IEnumerable` items are no longer counted
as sections. As a result, `NumberOfSections` now correctly reflects the
number of actual groups, preventing header/footer templates from
appearing for non-grouped items.

---

### Issues Fixed

Fixes #29141

### Test Case

Tests for this fix are included in this PR:
- `src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs` — HostApp
page with a `CollectionView` bound to a flat `ObservableCollection`,
with radio buttons to toggle `IsGrouped`, `GroupHeaderTemplate`, and
`GroupFooterTemplate` at runtime.
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs`
— NUnit UI test verifying that group header/footer template views are
NOT shown when the source collection is not grouped.

> **Note:** The test is currently excluded from Windows (unrelated
NullReferenceException — see #28824) and Android (separate fix in PR
#28886). It runs on iOS and MacCatalyst.

### Platforms Tested

- [x] iOS
- [x] Android
- [x] Mac
- [ ] Windows
</details>

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
github-actions Bot pushed a commit that referenced this pull request Mar 20, 2026
### Root Cause of the issue



- The failing test: `SetVisibility(Visibility.Collapsed)` device test on
iOS.

  Why it fails: PR #28983's fix maps Visibility → MapIsRunning in
  ActivityIndicatorHandler, which bypasses the standard
ViewExtensions.UpdateVisibility path. The standard path calls Collapse()
to
add a CollapseConstraint (an NSLayoutConstraint that zeros the view's
size).
The PR's UpdateIsRunning only sets Hidden = true — it never calls
Collapse()
- Crash in the FeatureMatrix Navigation Page Scenario in the iOS 26
PR #34326 added an else block in UpdateBarTextColor() that explicitly
sets BackButtonAppearance = null, BackIndicatorImage = null, and
BackIndicatorTransitionMaskImage = null on the navigation bar when no
custom color is applied. On iOS versions before 26, assigning null to
these properties was treated as "use system defaults." On iOS 26, the
Liquid Glass rendering pipeline reads these properties during push/pop
navigation transitions and throws an exception when it encounters an
explicit null — it expects either an unset property or a valid object.
Since useCustomColor is false by default (no IconColor set), this
crashes on every standard page navigation.
- Setting ThumbTintList = null in the else block removes the tint
entirely, causing the thumb to appear white instead of the default blue,
because SwitchCompat does not re-resolve its theme colors once the tint
list is cleared.
- SetAdjustViewBounds(false) was being applied to all images regardless
of their Aspect value. When this property is false, Android’s ImageView
does not resize itself based on the image’s intrinsic aspect ratio and
instead expands to fill the available space. As a result, an Image
control with the default AspectFit setting ignored its height constraint
and overflowed its container, causing the image to appear taller than
expected in the screenshot test.(LoadAndVerifyGif, ThemeRelated feature
tests)
- PR #29144 changed the group-detection guard in ObservableGroupedSource
(iOS and Android) from is IEnumerable to is ICollection to prevent
strings (which implement IEnumerable<char>) from being treated as
groups.
While the intent was correct, the change was too broad. Custom group
types that implement only IEnumerable<T> were also excluded. As a
result, _groupCount became zero on iOS and _groups remained empty on
Android, causing grouped CollectionView rendering failures and
IndexOutOfRangeException during Add/Remove operations.
- StepperHandler.iOS.cs compiles for both iOS and Mac Catalyst. On Mac
Catalyst / macOS 26, OperatingSystem.IsIOS() and IsIOSVersionAtLeast(26)
both return true, and the screen is always landscape. As a result, the
20pt glass pill compensation was incorrectly applied, inflating
GetDesiredSize(1,1) to width = 21. (Native View Bounding Box is not
empty - device Test failures)
- In PR #33428, the WindowInsetsCompat.Builder block in
MauiWindowInsetListener.ApplyDefaultWindowInsets was simplified to
return insets; to standardize inset handling. This change was unrelated
to the actual fix for #33344, which only required passing the bottom
inset through as unconsumed.
As part of that refactor, top inset consumption was also removed,
changing the prior contract where the top inset was consumed when
appBarHasContent = true. While normal safe-area scenarios worked
correctly, transient layout states (e.g., temporary Height = 0 during
keyboard dismissal, rotation, animation, or dynamic item generation)
triggered a second inset dispatch. In those moments, the top inset
satisfied the overlap condition and was applied to content before
SafeAreaExtensions could normalize it, causing test failures. Bottom
insets did not regress because their overlap condition cannot be met in
the same transient state. (EntryScrollTest,
HorizontalStackLayout_Spacing_WithLandscape,
VerticalStackLayout_Spacing_WithLandscape and so on failures)

### Description of Change



- Handles the three Visibility cases the same way as
ViewExtensions.UpdateVisibility:

`Visible`: Calls Inflate() (restores layout size) and sets Hidden =
false — identical to UpdateVisibility. Additionally starts/stops the
animation based on IsRunning.
`Hidden`: Calls Inflate() (preserves layout space) and sets Hidden =
true — identical to UpdateVisibility. The indicator keeps its layout
footprint but is invisible.
`Collapsed`: Sets Hidden = true and calls Collapse() (zeros out layout
size via constraints) — identical to UpdateVisibility. The indicator is
both invisible and takes up no space.
- Removed the else block entirely. When no custom color is applied,
these properties should remain untouched. The system defaults work
correctly on their own — there is no need to explicitly reset them to
null
- Removed the else block from UpdateThumbColor in SwitchExtensions.cs.
The default thumb color is managed by SwitchCompat internally from the
Material theme, so no explicit reset is needed.
- Restored the correct logic in ImageViewExtensions.UpdateAspect to call
SetAdjustViewBounds based on the image’s Aspect value:
- The guard has been updated from is ICollection to is IEnumerable &&
not string in the ObservableGroupedSource implementations for both iOS
and Android (GroupsCount(), UpdateGroupTracking(), Add(), Remove()).
This change specifically excludes string while allowing legitimate
custom group types that implement only IEnumerable<T>. The fix restores
the behavior for Issue22320 while keeping all Issue29141 scenarios
working correctly.
-Added !OperatingSystem.IsMacCatalyst() to the guard condition in
GetDesiredSize, restricting the 20pt compensation to real iOS 26+ only —
as intended in the original PR comment.
- Restored the original behavior by consuming the top inset when
appBarHasContent = true, while continuing to pass the bottom inset
through unconsumed (the only change required for #33344). This retains
the Android edge-to-edge fix and restores deterministic safe-area
handling.

### Testing related description of change
EditorNoOverlapAfterRotateToLandscape,
EditorNoOverlapAfterRotateToPortrait,
EntryFocusedShouldNotCauseGapAfterRotation Added cropLeft to remove the
navbar on Android and re-saved the image due to entry text changes in
this commit –
8d17a6d,
91047fb.

DrawStringShouldDrawText – The automation ID set to GraphicsView was not
found by Appium on the Windows platform, so a test condition was added
for Windows to take the image directly instead of waiting for the
GraphicsView.

Added the base images for iOS 26 and Mac that were not added previously.

Re-saved the images that failed due to the wrong iOS version image being
added in the PR.

Re-saved the test images that failed due to this fix PR:
#31254 — e.g.,
GraphicsViewFeatureTests and others.
 
Resaved the slider-related test images due to this fix PR —
#34064.

### Issues Fixed




Fixes #34437 



### Tested the behaviour in the following platforms



- [x] iOS
- [x] Mac

---------

Co-authored-by: SyedAbdulAzeem <syedabdulazeem.a@syncfusion.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
Co-authored-by: TamilarasanSF4853 <tamilarasan.velu@syncfusion.com>
Co-authored-by: LogishaSelvarajSF4525 <logisha.selvaraj@syncfusion.com>
github-actions Bot added a commit that referenced this pull request Mar 22, 2026
…tems when IsGrouped was true for an ObservableCollection (#29144)

<!-- 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!

## Issue 1: Group header and footer templates not updating correctly at
runtime on iOS.

### Root Cause

The mapper for `GroupFooterTemplateProperty` and
`GroupHeaderTemplateProperty` in `GroupableItemsViewHandler` was
conditionally compiled with `#if WINDOWS || __ANDROID__ || TIZEN`,
meaning it was excluded from iOS builds. As a result, changing the
template at runtime on iOS had no effect and templates were never
displayed.

### Description of Change

Removed the `#if WINDOWS || __ANDROID__ || TIZEN` preprocessor guard
from `GroupableItemsViewHandler.cs`, making the
`GroupFooterTemplateProperty` and `GroupHeaderTemplateProperty` mappers
active on all platforms including iOS. Both mappers call `MapIsGrouped`,
which triggers `UpdateItemsSource()` and refreshes the grouping state.

---

## Issue 2: Group header/footer templates incorrectly applied to all
items in a flat ObservableCollection when `IsGrouped = true`.

### Root Cause

In `ObservableGroupedSource.cs` (iOS), the `GroupsCount()` method
iterated over all items in `_groupSource` and counted every item,
regardless of whether it was an `IEnumerable` (i.e., an actual group).
When `IsGrouped = true` but the source was a flat
`ObservableCollection<T>` (non-grouped), each non-grouped item was
counted as a section, causing `NumberOfSections` to be inflated. This
led to header and footer templates being incorrectly applied to every
item.

### Description of Change

Modified `GroupsCount()` to only increment the count for items that
implement `IEnumerable`. Non-`IEnumerable` items are no longer counted
as sections. As a result, `NumberOfSections` now correctly reflects the
number of actual groups, preventing header/footer templates from
appearing for non-grouped items.

---

### Issues Fixed

Fixes #29141

### Test Case

Tests for this fix are included in this PR:
- `src/Controls/tests/TestCases.HostApp/Issues/Issue29141.cs` — HostApp
page with a `CollectionView` bound to a flat `ObservableCollection`,
with radio buttons to toggle `IsGrouped`, `GroupHeaderTemplate`, and
`GroupFooterTemplate` at runtime.
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29141.cs`
— NUnit UI test verifying that group header/footer template views are
NOT shown when the source collection is not grouped.

> **Note:** The test is currently excluded from Windows (unrelated
NullReferenceException — see #28824) and Android (separate fix in PR
#28886). It runs on iOS and MacCatalyst.

### Platforms Tested

- [x] iOS
- [x] Android
- [x] Mac
- [ ] Windows
</details>

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
github-actions Bot pushed a commit that referenced this pull request Mar 22, 2026
### Root Cause of the issue



- The failing test: `SetVisibility(Visibility.Collapsed)` device test on
iOS.

  Why it fails: PR #28983's fix maps Visibility → MapIsRunning in
  ActivityIndicatorHandler, which bypasses the standard
ViewExtensions.UpdateVisibility path. The standard path calls Collapse()
to
add a CollapseConstraint (an NSLayoutConstraint that zeros the view's
size).
The PR's UpdateIsRunning only sets Hidden = true — it never calls
Collapse()
- Crash in the FeatureMatrix Navigation Page Scenario in the iOS 26
PR #34326 added an else block in UpdateBarTextColor() that explicitly
sets BackButtonAppearance = null, BackIndicatorImage = null, and
BackIndicatorTransitionMaskImage = null on the navigation bar when no
custom color is applied. On iOS versions before 26, assigning null to
these properties was treated as "use system defaults." On iOS 26, the
Liquid Glass rendering pipeline reads these properties during push/pop
navigation transitions and throws an exception when it encounters an
explicit null — it expects either an unset property or a valid object.
Since useCustomColor is false by default (no IconColor set), this
crashes on every standard page navigation.
- Setting ThumbTintList = null in the else block removes the tint
entirely, causing the thumb to appear white instead of the default blue,
because SwitchCompat does not re-resolve its theme colors once the tint
list is cleared.
- SetAdjustViewBounds(false) was being applied to all images regardless
of their Aspect value. When this property is false, Android’s ImageView
does not resize itself based on the image’s intrinsic aspect ratio and
instead expands to fill the available space. As a result, an Image
control with the default AspectFit setting ignored its height constraint
and overflowed its container, causing the image to appear taller than
expected in the screenshot test.(LoadAndVerifyGif, ThemeRelated feature
tests)
- PR #29144 changed the group-detection guard in ObservableGroupedSource
(iOS and Android) from is IEnumerable to is ICollection to prevent
strings (which implement IEnumerable<char>) from being treated as
groups.
While the intent was correct, the change was too broad. Custom group
types that implement only IEnumerable<T> were also excluded. As a
result, _groupCount became zero on iOS and _groups remained empty on
Android, causing grouped CollectionView rendering failures and
IndexOutOfRangeException during Add/Remove operations.
- StepperHandler.iOS.cs compiles for both iOS and Mac Catalyst. On Mac
Catalyst / macOS 26, OperatingSystem.IsIOS() and IsIOSVersionAtLeast(26)
both return true, and the screen is always landscape. As a result, the
20pt glass pill compensation was incorrectly applied, inflating
GetDesiredSize(1,1) to width = 21. (Native View Bounding Box is not
empty - device Test failures)
- In PR #33428, the WindowInsetsCompat.Builder block in
MauiWindowInsetListener.ApplyDefaultWindowInsets was simplified to
return insets; to standardize inset handling. This change was unrelated
to the actual fix for #33344, which only required passing the bottom
inset through as unconsumed.
As part of that refactor, top inset consumption was also removed,
changing the prior contract where the top inset was consumed when
appBarHasContent = true. While normal safe-area scenarios worked
correctly, transient layout states (e.g., temporary Height = 0 during
keyboard dismissal, rotation, animation, or dynamic item generation)
triggered a second inset dispatch. In those moments, the top inset
satisfied the overlap condition and was applied to content before
SafeAreaExtensions could normalize it, causing test failures. Bottom
insets did not regress because their overlap condition cannot be met in
the same transient state. (EntryScrollTest,
HorizontalStackLayout_Spacing_WithLandscape,
VerticalStackLayout_Spacing_WithLandscape and so on failures)

### Description of Change



- Handles the three Visibility cases the same way as
ViewExtensions.UpdateVisibility:

`Visible`: Calls Inflate() (restores layout size) and sets Hidden =
false — identical to UpdateVisibility. Additionally starts/stops the
animation based on IsRunning.
`Hidden`: Calls Inflate() (preserves layout space) and sets Hidden =
true — identical to UpdateVisibility. The indicator keeps its layout
footprint but is invisible.
`Collapsed`: Sets Hidden = true and calls Collapse() (zeros out layout
size via constraints) — identical to UpdateVisibility. The indicator is
both invisible and takes up no space.
- Removed the else block entirely. When no custom color is applied,
these properties should remain untouched. The system defaults work
correctly on their own — there is no need to explicitly reset them to
null
- Removed the else block from UpdateThumbColor in SwitchExtensions.cs.
The default thumb color is managed by SwitchCompat internally from the
Material theme, so no explicit reset is needed.
- Restored the correct logic in ImageViewExtensions.UpdateAspect to call
SetAdjustViewBounds based on the image’s Aspect value:
- The guard has been updated from is ICollection to is IEnumerable &&
not string in the ObservableGroupedSource implementations for both iOS
and Android (GroupsCount(), UpdateGroupTracking(), Add(), Remove()).
This change specifically excludes string while allowing legitimate
custom group types that implement only IEnumerable<T>. The fix restores
the behavior for Issue22320 while keeping all Issue29141 scenarios
working correctly.
-Added !OperatingSystem.IsMacCatalyst() to the guard condition in
GetDesiredSize, restricting the 20pt compensation to real iOS 26+ only —
as intended in the original PR comment.
- Restored the original behavior by consuming the top inset when
appBarHasContent = true, while continuing to pass the bottom inset
through unconsumed (the only change required for #33344). This retains
the Android edge-to-edge fix and restores deterministic safe-area
handling.

### Testing related description of change
EditorNoOverlapAfterRotateToLandscape,
EditorNoOverlapAfterRotateToPortrait,
EntryFocusedShouldNotCauseGapAfterRotation Added cropLeft to remove the
navbar on Android and re-saved the image due to entry text changes in
this commit –
8d17a6d,
91047fb.

DrawStringShouldDrawText – The automation ID set to GraphicsView was not
found by Appium on the Windows platform, so a test condition was added
for Windows to take the image directly instead of waiting for the
GraphicsView.

Added the base images for iOS 26 and Mac that were not added previously.

Re-saved the images that failed due to the wrong iOS version image being
added in the PR.

Re-saved the test images that failed due to this fix PR:
#31254 — e.g.,
GraphicsViewFeatureTests and others.
 
Resaved the slider-related test images due to this fix PR —
#34064.

### Issues Fixed




Fixes #34437 



### Tested the behaviour in the following platforms



- [x] iOS
- [x] Mac

---------

Co-authored-by: SyedAbdulAzeem <syedabdulazeem.a@syncfusion.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
Co-authored-by: TamilarasanSF4853 <tamilarasan.velu@syncfusion.com>
Co-authored-by: LogishaSelvarajSF4525 <logisha.selvaraj@syncfusion.com>
KarthikRajaKalaimani pushed a commit to KarthikRajaKalaimani/maui that referenced this pull request Mar 23, 2026
- The failing test: `SetVisibility(Visibility.Collapsed)` device test on
iOS.

  Why it fails: PR dotnet#28983's fix maps Visibility → MapIsRunning in
  ActivityIndicatorHandler, which bypasses the standard
ViewExtensions.UpdateVisibility path. The standard path calls Collapse()
to
add a CollapseConstraint (an NSLayoutConstraint that zeros the view's
size).
The PR's UpdateIsRunning only sets Hidden = true — it never calls
Collapse()
- Crash in the FeatureMatrix Navigation Page Scenario in the iOS 26
PR dotnet#34326 added an else block in UpdateBarTextColor() that explicitly
sets BackButtonAppearance = null, BackIndicatorImage = null, and
BackIndicatorTransitionMaskImage = null on the navigation bar when no
custom color is applied. On iOS versions before 26, assigning null to
these properties was treated as "use system defaults." On iOS 26, the
Liquid Glass rendering pipeline reads these properties during push/pop
navigation transitions and throws an exception when it encounters an
explicit null — it expects either an unset property or a valid object.
Since useCustomColor is false by default (no IconColor set), this
crashes on every standard page navigation.
- Setting ThumbTintList = null in the else block removes the tint
entirely, causing the thumb to appear white instead of the default blue,
because SwitchCompat does not re-resolve its theme colors once the tint
list is cleared.
- SetAdjustViewBounds(false) was being applied to all images regardless
of their Aspect value. When this property is false, Android’s ImageView
does not resize itself based on the image’s intrinsic aspect ratio and
instead expands to fill the available space. As a result, an Image
control with the default AspectFit setting ignored its height constraint
and overflowed its container, causing the image to appear taller than
expected in the screenshot test.(LoadAndVerifyGif, ThemeRelated feature
tests)
- PR dotnet#29144 changed the group-detection guard in ObservableGroupedSource
(iOS and Android) from is IEnumerable to is ICollection to prevent
strings (which implement IEnumerable<char>) from being treated as
groups.
While the intent was correct, the change was too broad. Custom group
types that implement only IEnumerable<T> were also excluded. As a
result, _groupCount became zero on iOS and _groups remained empty on
Android, causing grouped CollectionView rendering failures and
IndexOutOfRangeException during Add/Remove operations.
- StepperHandler.iOS.cs compiles for both iOS and Mac Catalyst. On Mac
Catalyst / macOS 26, OperatingSystem.IsIOS() and IsIOSVersionAtLeast(26)
both return true, and the screen is always landscape. As a result, the
20pt glass pill compensation was incorrectly applied, inflating
GetDesiredSize(1,1) to width = 21. (Native View Bounding Box is not
empty - device Test failures)
- In PR dotnet#33428, the WindowInsetsCompat.Builder block in
MauiWindowInsetListener.ApplyDefaultWindowInsets was simplified to
return insets; to standardize inset handling. This change was unrelated
to the actual fix for dotnet#33344, which only required passing the bottom
inset through as unconsumed.
As part of that refactor, top inset consumption was also removed,
changing the prior contract where the top inset was consumed when
appBarHasContent = true. While normal safe-area scenarios worked
correctly, transient layout states (e.g., temporary Height = 0 during
keyboard dismissal, rotation, animation, or dynamic item generation)
triggered a second inset dispatch. In those moments, the top inset
satisfied the overlap condition and was applied to content before
SafeAreaExtensions could normalize it, causing test failures. Bottom
insets did not regress because their overlap condition cannot be met in
the same transient state. (EntryScrollTest,
HorizontalStackLayout_Spacing_WithLandscape,
VerticalStackLayout_Spacing_WithLandscape and so on failures)

- Handles the three Visibility cases the same way as
ViewExtensions.UpdateVisibility:

`Visible`: Calls Inflate() (restores layout size) and sets Hidden =
false — identical to UpdateVisibility. Additionally starts/stops the
animation based on IsRunning.
`Hidden`: Calls Inflate() (preserves layout space) and sets Hidden =
true — identical to UpdateVisibility. The indicator keeps its layout
footprint but is invisible.
`Collapsed`: Sets Hidden = true and calls Collapse() (zeros out layout
size via constraints) — identical to UpdateVisibility. The indicator is
both invisible and takes up no space.
- Removed the else block entirely. When no custom color is applied,
these properties should remain untouched. The system defaults work
correctly on their own — there is no need to explicitly reset them to
null
- Removed the else block from UpdateThumbColor in SwitchExtensions.cs.
The default thumb color is managed by SwitchCompat internally from the
Material theme, so no explicit reset is needed.
- Restored the correct logic in ImageViewExtensions.UpdateAspect to call
SetAdjustViewBounds based on the image’s Aspect value:
- The guard has been updated from is ICollection to is IEnumerable &&
not string in the ObservableGroupedSource implementations for both iOS
and Android (GroupsCount(), UpdateGroupTracking(), Add(), Remove()).
This change specifically excludes string while allowing legitimate
custom group types that implement only IEnumerable<T>. The fix restores
the behavior for Issue22320 while keeping all Issue29141 scenarios
working correctly.
-Added !OperatingSystem.IsMacCatalyst() to the guard condition in
GetDesiredSize, restricting the 20pt compensation to real iOS 26+ only —
as intended in the original PR comment.
- Restored the original behavior by consuming the top inset when
appBarHasContent = true, while continuing to pass the bottom inset
through unconsumed (the only change required for dotnet#33344). This retains
the Android edge-to-edge fix and restores deterministic safe-area
handling.

EditorNoOverlapAfterRotateToLandscape,
EditorNoOverlapAfterRotateToPortrait,
EntryFocusedShouldNotCauseGapAfterRotation Added cropLeft to remove the
navbar on Android and re-saved the image due to entry text changes in
this commit –
dotnet@8d17a6d,
dotnet@91047fb.

DrawStringShouldDrawText – The automation ID set to GraphicsView was not
found by Appium on the Windows platform, so a test condition was added
for Windows to take the image directly instead of waiting for the
GraphicsView.

Added the base images for iOS 26 and Mac that were not added previously.

Re-saved the images that failed due to the wrong iOS version image being
added in the PR.

Re-saved the test images that failed due to this fix PR:
dotnet#31254 — e.g.,
GraphicsViewFeatureTests and others.

Resaved the slider-related test images due to this fix PR —
dotnet#34064.

Fixes dotnet#34437

- [x] iOS
- [x] Mac

---------

Co-authored-by: SyedAbdulAzeem <syedabdulazeem.a@syncfusion.com>
Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com>
Co-authored-by: TamilarasanSF4853 <tamilarasan.velu@syncfusion.com>
Co-authored-by: LogishaSelvarajSF4525 <logisha.selvaraj@syncfusion.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution p/1 Work that is important, and has been scheduled for release in this or an upcoming sprint partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios 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-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) s/agent-suggestions-implemented Maintainer applies when PR author adopts agent's recommendation

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[iOS] Group Header/Footer Repeated for All Items When IsGrouped is True for ObservableCollection in CollectionView

9 participants