Skip to content

Perf: Eliminate unnecessary List allocations in Accordion control#372

Merged
PaulAndersonS merged 2 commits into
mainfrom
paulandersons/ideal-waffle
Jun 1, 2026
Merged

Perf: Eliminate unnecessary List allocations in Accordion control#372
PaulAndersonS merged 2 commits into
mainfrom
paulandersons/ideal-waffle

Conversation

@PaulAndersonS
Copy link
Copy Markdown
Collaborator

Root Cause of the Issue

The SfAccordion and AccordionItemView classes used Items.ToList().FindAll() and Items.ToList().FirstOrDefault() patterns in multiple methods. Since Items is an ObservableCollection<AccordionItem>, calling .ToList() allocates a full copy of the collection on every invocation — only to immediately filter or search it. This creates unnecessary GC pressure during user interactions (expand/collapse, keyboard navigation).

Description of Change

Replaced all Items.ToList().FindAll(predicate) and Items.ToList().FirstOrDefault(predicate) calls with direct foreach iteration over the ObservableCollection:

Method Before After
SfAccordion.UpdateSelection() Items.ToList().FindAll(...) foreach with counter
SfAccordion.UpdateAccordionItemsBasedOnExpandModes() Items.ToList().FindAll(...) foreach building filtered list directly
SfAccordion.OnKeyDown() Items.ToList().FirstOrDefault(...) foreach with early break
AccordionItemView.CanCollapseItemOnSingleAndMultipleExpandMode() Accordion.Items.ToList().FindAll(...) foreach with counter and early exit

Impact: Eliminates 4 unnecessary List<T> allocations per operation, reducing GC pressure during accordion interactions.

Unit tests added: 4 new tests covering edge cases for the refactored methods.

Issues Fixed

N/A (performance improvement)

Screenshots

N/A (no visual changes)

Replace Items.ToList().FindAll() and Items.ToList().FirstOrDefault() with
direct iteration over the ObservableCollection. The previous pattern
allocated a full copy of the Items collection on every call just to
perform a filter or search, creating unnecessary GC pressure during
expand/collapse and keyboard navigation operations.

Changes:
- SfAccordion.UpdateSelection(): Use foreach loop instead of ToList().FindAll()
- SfAccordion.UpdateAccordionItemsBasedOnExpandModes(): Build filtered list
  directly without copying the entire collection first
- SfAccordion.OnKeyDown(): Use foreach with early break instead of
  ToList().FirstOrDefault()
- AccordionItemView.CanCollapseItemOnSingleAndMultipleExpandMode(): Count
  expanded items with foreach instead of allocating a filtered list

Also adds unit tests verifying the refactored methods maintain correct
behavior for edge cases (no items selected, null AccordionItemView,
empty collections, multiple expanded items in Single mode).

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

@copilot resolve the merge conflicts in this pull request

…affle

# Conflicts:
#	maui/src/Accordion/AccordionItemView.cs
#	maui/src/Accordion/SfAccordion.cs
Copy link
Copy Markdown
Contributor

Copilot AI commented May 27, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts have been resolved in commit cfaab8e. Both AccordionItemView.cs and SfAccordion.cs had conflicts where main's Items.Where(...).ToList() approach overlapped with this PR's foreach loop approach. Kept the foreach implementations (more performant — avoids the intermediate List<T> allocation entirely) and also fixed the indentation in the OnKeyDown block.

@AmalRajUmapathySelvam
Copy link
Copy Markdown
Collaborator

Changes are fine.

@PaulAndersonS PaulAndersonS merged commit 046d520 into main Jun 1, 2026
1 check passed
@PaulAndersonS PaulAndersonS added this to the v1.0.11 milestone Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants