Skip to content

Conversation

@NanthiniMahalingam
Copy link
Contributor

@NanthiniMahalingam NanthiniMahalingam commented Dec 15, 2025

Root cause

  • When the ItemSizingStrategy is set to measure the first item, the collection view’s grouped item header or footer template size is taken from the first item’s size instead of the actual size of the grouped item header or footer template.

Description of changes

  • I have ignored the first measured item’s size when applying it to the grouped header or footer template, the collection view header or footer view, and the collection view header or footer template in PreferredLayoutAttributesFittingAttributes of TemplatedCell2.

Issues Fixed

Fixes #33130

Validated the behaviour in the following platforms

  • Android
  • Windows ,
  • iOS,
  • MacOS

Output

iOS

Before After
issue33130_iOS_before.mov
Issue33130_iOS_after.mov

macOS

Before After
issue33130_mac_before.mov
Issue33130_mac_after.mov

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Dec 15, 2025
@karthikraja-arumugam karthikraja-arumugam added the community ✨ Community Contribution label Dec 15, 2025
@sheiksyedm sheiksyedm added platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Dec 15, 2025
@sheiksyedm sheiksyedm marked this pull request as ready for review December 15, 2025 14:42
Copilot AI review requested due to automatic review settings December 15, 2025 14:42
Copy link
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.

Pull request overview

This PR fixes a CollectionView issue on iOS and macOS where group headers and footers incorrectly inherit the size of the first measured item when the ItemSizingStrategy is set to MeasureFirstItem. The fix introduces a boolean flag isSupplementaryView to distinguish supplementary views (headers/footers) from regular item cells, ensuring headers/footers are always measured directly and never use the cached first-item measurement.

Key Changes:

  • Added flag to prevent headers/footers from using the first-item measurement cache
  • Updated measurement logic to conditionally apply cached measurements only to item cells
  • Added comprehensive UI test to verify the fix works correctly

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs Adds isSupplementaryView flag and updates measurement logic to skip cached measurements for headers/footers
src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs Sets the isSupplementaryView flag when configuring supplementary views
src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs Explicitly clears the isSupplementaryView flag for regular item cells
src/Controls/src/Core/Handlers/Items2/iOS/GroupableItemsViewController2.cs Sets the isSupplementaryView flag for group headers and footers
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33130.cs NUnit test that verifies header height remains constant when ItemSizingStrategy changes
src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml XAML test page with grouped CollectionView and button to switch sizing strategy
src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml.cs Code-behind with view models demonstrating the group header sizing issue

Size _cachedConstraints;

// Indicates the cell is being used as a supplementary view (group header/footer)
internal bool isSupplementaryView = false;
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The field isSupplementaryView does not follow C# naming conventions. Internal fields should use PascalCase with an underscore prefix (e.g., _isSupplementaryView) to be consistent with other fields in this class like _measureInvalidated, _needsArrange, _measuredSize, and _cachedConstraints.

Copilot uses AI. Check for mistakes.
}
}

public class GroupHeaderTestAnimalGroup : ObservableCollection<GroupHeaderTestAnimal>
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The class name GroupHeaderTestAnimalGroup is verbose and redundant. Following the naming pattern used in other test files (e.g., Issue12374Model), this should be named AnimalGroup or Issue33130AnimalGroup to be more concise while maintaining clarity.

Copilot uses AI. Check for mistakes.
Comment on lines 25 to 61
public ObservableCollection<GroupHeaderTestAnimalGroup> Animals { get; set; }

public GroupedAnimalsViewModel()
{
Animals = new ObservableCollection<GroupHeaderTestAnimalGroup>
{
new GroupHeaderTestAnimalGroup("Bears")
{
new GroupHeaderTestAnimal { Name = "Grizzly Bear", Location = "North America", ImageUrl = "bear.jpg" },
new GroupHeaderTestAnimal { Name = "Polar Bear", Location = "Arctic", ImageUrl = "bear.jpg" },
},
new GroupHeaderTestAnimalGroup("Monkeys")
{
new GroupHeaderTestAnimal { Name = "Baboon", Location = "Africa", ImageUrl = "monkey.jpg" },
new GroupHeaderTestAnimal { Name = "Capuchin Monkey", Location = "South America", ImageUrl = "monkey.jpg" },
new GroupHeaderTestAnimal { Name = "Spider Monkey", Location = "Central America", ImageUrl = "monkey.jpg" },
},
new GroupHeaderTestAnimalGroup("Elephants")
{
new GroupHeaderTestAnimal { Name = "African Elephant", Location = "Africa", ImageUrl = "elephant.jpg" },
new GroupHeaderTestAnimal { Name = "Asian Elephant", Location = "Asia", ImageUrl = "elephant.jpg" },
}
};
}
}

public class GroupHeaderTestAnimalGroup : ObservableCollection<GroupHeaderTestAnimal>
{
public string Name { get; set; }

public GroupHeaderTestAnimalGroup(string name) : base()
{
Name = name;
}
}

public class GroupHeaderTestAnimal
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The class name GroupHeaderTestAnimal is verbose with redundant "GroupHeaderTest" prefix. Following the naming pattern used in other test files (e.g., Issue12374Model), this should be named Animal or Issue33130Animal to be more concise while maintaining clarity.

Suggested change
public ObservableCollection<GroupHeaderTestAnimalGroup> Animals { get; set; }
public GroupedAnimalsViewModel()
{
Animals = new ObservableCollection<GroupHeaderTestAnimalGroup>
{
new GroupHeaderTestAnimalGroup("Bears")
{
new GroupHeaderTestAnimal { Name = "Grizzly Bear", Location = "North America", ImageUrl = "bear.jpg" },
new GroupHeaderTestAnimal { Name = "Polar Bear", Location = "Arctic", ImageUrl = "bear.jpg" },
},
new GroupHeaderTestAnimalGroup("Monkeys")
{
new GroupHeaderTestAnimal { Name = "Baboon", Location = "Africa", ImageUrl = "monkey.jpg" },
new GroupHeaderTestAnimal { Name = "Capuchin Monkey", Location = "South America", ImageUrl = "monkey.jpg" },
new GroupHeaderTestAnimal { Name = "Spider Monkey", Location = "Central America", ImageUrl = "monkey.jpg" },
},
new GroupHeaderTestAnimalGroup("Elephants")
{
new GroupHeaderTestAnimal { Name = "African Elephant", Location = "Africa", ImageUrl = "elephant.jpg" },
new GroupHeaderTestAnimal { Name = "Asian Elephant", Location = "Asia", ImageUrl = "elephant.jpg" },
}
};
}
}
public class GroupHeaderTestAnimalGroup : ObservableCollection<GroupHeaderTestAnimal>
{
public string Name { get; set; }
public GroupHeaderTestAnimalGroup(string name) : base()
{
Name = name;
}
}
public class GroupHeaderTestAnimal
public ObservableCollection<Issue33130AnimalGroup> Animals { get; set; }
public GroupedAnimalsViewModel()
{
Animals = new ObservableCollection<Issue33130AnimalGroup>
{
new Issue33130AnimalGroup("Bears")
{
new Issue33130Animal { Name = "Grizzly Bear", Location = "North America", ImageUrl = "bear.jpg" },
new Issue33130Animal { Name = "Polar Bear", Location = "Arctic", ImageUrl = "bear.jpg" },
},
new Issue33130AnimalGroup("Monkeys")
{
new Issue33130Animal { Name = "Baboon", Location = "Africa", ImageUrl = "monkey.jpg" },
new Issue33130Animal { Name = "Capuchin Monkey", Location = "South America", ImageUrl = "monkey.jpg" },
new Issue33130Animal { Name = "Spider Monkey", Location = "Central America", ImageUrl = "monkey.jpg" },
},
new Issue33130AnimalGroup("Elephants")
{
new Issue33130Animal { Name = "African Elephant", Location = "Africa", ImageUrl = "elephant.jpg" },
new Issue33130Animal { Name = "Asian Elephant", Location = "Asia", ImageUrl = "elephant.jpg" },
}
};
}
}
public class Issue33130AnimalGroup : ObservableCollection<Issue33130Animal>
{
public string Name { get; set; }
public Issue33130AnimalGroup(string name) : base()
{
Name = name;
}
}
public class Issue33130Animal

Copilot uses AI. Check for mistakes.
var heightDifference = Math.Abs(headerRectBefore.Height - headerRectAfter.Height);

// Assert that the height difference is minimal (less than 5 pixels tolerance)
Assert.That(heightDifference, Is.EqualTo(0),
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The assertion uses Is.EqualTo(0) which expects the height difference to be exactly zero. However, the comment on line 37 mentions "Allow for small rounding differences". This is inconsistent. If you want to allow for small rounding differences, the assertion should use a tolerance (e.g., Is.EqualTo(0).Within(1) or Is.LessThanOrEqualTo(1)) instead of requiring exact equality. As written, the test may fail due to minor floating-point precision differences across platforms.

Suggested change
Assert.That(heightDifference, Is.EqualTo(0),
Assert.That(heightDifference, Is.EqualTo(0).Within(5),

Copilot uses AI. Check for mistakes.
{
TemplatedCell2.ScrollDirection = ScrollDirection;

// Ensure this cell is treated as a regular item cell (not a supplementary view)
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The comment "Ensure this cell is treated as a regular item cell (not a supplementary view)" is helpful, but it would be more informative to explain why this is necessary. Consider expanding it to: "Ensure this cell is treated as a regular item cell (not a supplementary view) so it can use the cached first-item measurement for MeasureFirstItem strategy" to provide better context about the fix's purpose.

Suggested change
// Ensure this cell is treated as a regular item cell (not a supplementary view)
// Ensure this cell is treated as a regular item cell (not a supplementary view)
// so it can use the cached first-item measurement for MeasureFirstItem strategy

Copilot uses AI. Check for mistakes.
@PureWeen
Copy link
Member

/backport to release/10.0.1xx-sr2

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx-sr2 (link to workflow run)

Text="ItemSizingStrategy: MeasureAllItems"/>
</StackLayout>

<local:CollectionView2 Grid.Row="1"
Copy link
Member

Choose a reason for hiding this comment

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

Set this to just CollectionView if this is passing on both CV1 and CV2

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Set this to just CollectionView if this is passing on both CV1 and CV2

Hi @PureWeen ,
I have changed CollectionView2 to CollectionView to ensure the test case passes on both CV1 and CV2.

PureWeen pushed a commit that referenced this pull request Dec 15, 2025
… size changes with ItemSizingStrategy (#33166)

Backport of #33161 to release/10.0.1xx-sr2

/cc @PureWeen @NanthiniMahalingam

---------

Co-authored-by: NanthiniMahalingam <[email protected]>
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 platform/ios

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NET 10] I6_Grouping - Grouping_with_variable_sized_items changing the 'ItemSizingStrategy' also changes the header size.

4 participants