본문 바로가기

Why CheckBoxes Break Selection in .NET MAUI CollectionView

@veedeeo 2025. 12. 21. 16:20

Understanding Dual Selection Authorities, UI–Model Conflicts, and Recycling Side Effects**

Many MAUI developers try to use a CheckBox inside a CollectionView to control selection —
while also relying on SelectionMode.

This leads to extremely confusing behaviors:

  • Tapping a CheckBox selects the row
  • Tapping the row changes the CheckBox
  • SelectedItem changes when you didn’t change it
  • Scrolling resets CheckBox states
  • Some items appear selected when they shouldn't
  • CheckBox state “jumps” between rows
  • SelectionChanged fires unexpectedly

These are not random bugs.
They are the direct consequence of two independent selection systems fighting each other:

  1. MAUI’s built-in Selection Engine
  2. Your CheckBox-bound model state

If both try to decide “which item is selected,” the result is unstable and unpredictable.

This article explains why CheckBoxes break selection inside CollectionView
and how to design a clean, stable selection system — without fighting MAUI’s virtualization engine.

 

Summary Card (TLDR)

Why CheckBoxes Break Selection in .NET MAUI CollectionView

1. Two independent systems try to control selection
A CheckBox updates IsSelected in your model, while CollectionView updates SelectedItem / SelectedItems.
These systems run at different times → state overwriting, double selection, and visual glitches occur.

2. CheckBox consumes the tap before CollectionView receives it
Because CheckBox is an interaction owner, its gesture blocks CollectionView’s built-in selection pipeline, causing:

  • Rows selecting at the wrong time
  • SelectionChanged firing unexpectedly
  • Check state drifting out of sync with row selection

3. Virtualization reuses UI containers, causing “ghost checks”
Recycled templates may carry old CheckBox states, showing checked or unchecked values on the wrong rows if the model isn’t the single source of truth.

4. SelectionMode + CheckBox = guaranteed conflict
SelectionMode controls row selection.
CheckBox controls boolean state.
Both try to represent “selection,” but they are not synchronized.
Mixing them always produces unstable behavior.

5. Scrolling triggers rebinding, which resets CheckBox state
When a container is reused, MAUI reassigns BindingContext → CheckBox temporarily displays stale UI states → selection feels random.

6. Production-safe solution: choose ONE selection authority

  • For multi-select → Use CheckBoxes only, set SelectionMode="None"
  • For row selection → Use SelectionMode only, remove CheckBoxes
  • Never combine the two

Core Principle:
Selection must come from either the model (CheckBox) or the CollectionView engine — never both.
Two selection systems cannot coexist inside a virtualized layout.

Why CheckBoxes Break Selection in .NET MAUI CollectionView


1. When You Add a CheckBox, You Create a Second Selection System

Inside a virtualized list, a CheckBox is not a simple toggle.
It is an interaction owner.

When tapped:

  • It intercepts the gesture
  • Updates itself synchronously
  • Modifies the viewmodel early
  • Competes with CollectionView’s selection logic

This creates a state conflict:

UI ActionCheckBox DecidesMAUI Selection Engine Decides
Tap on CheckBox “This item is selected or not.” “This row should be selected.”
Tap on row (No opinion) “Change SelectedItem.”
Scroll CheckBox UI is recycled BindingContext is reassigned

Because the two systems run independently:

The CheckBox and the built-in selection engine overwrite each other’s state.


2. Why Scrolling Randomly Changes CheckBox State

MAUI CollectionView uses virtualization:

  • UI templates (visual containers) are reused
  • A reused cell may previously have had CheckBox checked
  • When assigned a new BindingContext, UI state resets incorrectly
  • If the model and UI become out-of-sync, recycled visuals display stale values

This is why scrolling produces:

  • “Ghost checks”
  • CheckBox values appearing in the wrong rows
  • Selection jumping to items you didn't tap

Recycling is unforgiving if your UI holds state instead of your model.


3. Why Selecting One Row Changes the CheckBox in Another Row

This happens because:

✔ CheckBox modifies MyItem.IsSelected

✔ SelectionMode modifies SelectedItem

✔ MAUI updates visual selected state based on SelectedItem

✔ Both run OUT OF ORDER

Example sequence:

  1. Tap CheckBox on Item A
  2. CheckBox updates A.IsSelected
  3. CollectionView sees a tap → selects Item A
  4. Virtualization swaps container BindingContexts
  5. Template rebinding re-applies visual states
  6. SelectionChanged fires
  7. UI highlights item B (previously selected)
  8. CheckBox receives stale UI state, toggling unexpectedly

In short:

Two systems try to synchronize selection, but they run in different frames and different event orders.


4. Never Combine SelectionMode with CheckBoxes — They Are Mutually Exclusive

This is the single most important rule:

 
❌ SelectionMode + CheckBox → state conflict ✔ SelectionMode onlystable ✔ CheckBox onlystable

Why?

SelectionMode = Single / Multiple

MAUI manages:

  • Which row is selected
  • Which container is highlighted
  • Which BindingContexts should reflect selection state
  • How recycled cells apply selected visual states

Your CheckBox

Manages:

  • Boolean model state
  • Visual toggle
  • Gesture consumption
  • Two-way binding behavior

Two independent authorities → inevitable conflict.


5. The Correct Fix: Disable SelectionMode and Let CheckBox Own Selection

If your goal is:

  • Multi-select
  • Download list
  • User-controlled toggles
  • Checkbox-driven filtering
  • Batch operations

Then:

<CollectionView SelectionMode="None">
 
 

Bind CheckBox:

<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" />
 
 

This makes the CheckBox the sole selection authority.

Result:

  • No conflict
  • No ghost checks
  • No selection jumping
  • No recycled UI issues
  • No SelectionChanged misfires

This is the only stable architecture for CheckBox-driven selection.


6. When You Actually Need SelectionMode

If you want:

  • Navigation lists
  • Menu selection
  • “Highlight selected row” UX
  • Single-choice lists

Then:

✔ Use SelectionMode
❌ Remove CheckBoxes
 
 

Make CheckBox disappear and rely entirely on:

 
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
 
 

Highlight using VisualStateManager.


7. Recommended Patterns (Production-Proven)

Pattern A — CheckBox-driven selection (no SelectionMode)

Use when user selects items manually.

  • CheckBox bound to model
  • SelectionMode=None
  • Ignore SelectionChanged

Pattern B — UI-driven selection (no CheckBox)

Use when selecting a row navigates or changes state.

  • SelectionMode=Single
  • Visual states for selected appearance
  • No toggle UI inside the row

Pattern C — Hybrid only with explicit control

Extremely advanced; ignore unless absolutely required.

Requires:

  • Preventing CheckBox taps from modifying SelectedItem
  • Preventing SelectionMode from modifying IsSelected
  • Custom event routing
  • Manual update synchronization

Not recommended.


8. Final Expert Takeaway

If CheckBox selection is unstable in MAUI, it is not due to bugs —
it is due to architecture.

Because:

  • SelectionMode and CheckBox both maintain selection state
  • They operate at different layers
  • They receive gestures at different times
  • Recycled templates reuse stale visuals

This guarantees conflict.

The solution is simple:

Choose ONE selection authority:
CheckBox → OR → CollectionView.SelectionMode
Never both.

Once you enforce that rule,
selection becomes 100% predictable — even with fast scrolling, rapid taps, or large datasets.

veedeeo
@veedeeo :: .net MAUI·Netlify·SEO·웹 최적화 기술 블로그

.net MAUI·Netlify·SEO·웹 최적화 기술 블로그

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차