Skip to content

fix(maui): deliver Deactivated to the view model a parked view was activated with - #55

Open
michaelstonis wants to merge 2 commits into
developfrom
fix/maui-replaced-view-model-lifecycle
Open

michaelstonis wants to merge 2 commits into
developfrom
fix/maui-replaced-view-model-lifecycle

Conversation

@michaelstonis

@michaelstonis michaelstonis commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #54 (its commit shows here until it merges).

Why

With the opt-in recycled-row feature, a kept row can have its view model replaced while it is parked. When it then returned (or the list left the window), Deactivated went to the replacement, which had never been Activated, and the original, which had, got only Unregister(). Verified by a characterisation test on the base: original [Initialized, Activated, Attached, Detached], replacement [Deactivated, Initialized, Activated, Attached].

ReactiveUI's own HandleViewModelActivation deactivates the old view model before activating the new one; this follows that order. Details and sources are in review-follow-ups-research-2026-10-05.md on #56's branch.

What

  • ViewManager<TViewModel> (core) gains protected void OnLifecycle(TViewModel? viewModel, LifecycleEvent); the public OnLifecycle(view, …) forwards to it. No state, no virtual call, non-breaking.
  • MauiViewManager.DeactivateParked raises Deactivated to the parked view model, then unregisters the bindings, unregisters the original, and disposes the view. The replacement sees Initialized, Activated, Attached only. The view-level LifecycleEvents stream still emits Deactivated once.
  • Four tests: replaced then returned, replaced then list leaves window, taken away (null), and replaced view model already collected.

Only consumer view models implementing ILifecycleEventAware on an opted-in list were affected.

Verification

  • All four tests fail on the base and pass with the change.
  • dotnet build Stellar.slnf -c Release: 0 errors; Stellar.UnitTests 259/259; Stellar.Maui.UnitTests 202/202 on net10.0.
  • Not run on a device.

🤖 Generated with Claude Code

michaelstonis and others added 2 commits October 5, 2026 16:26
…cument the option

Passing 0 to a list that had never opted in created a watcher and a
PropertyChanged subscription for a list that keeps nothing.

Adds the README section for the option, tests that a list which has not
opted in is not watched and that opting in after rows are bound takes
effect, and puts every MAUI test class through UseStellarComponents so
results cannot depend on which class initialises ReactiveUI first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tivated with

When a kept recycled view's view model was replaced while it was parked,
Deactivated went to the replacement, which had never been activated,
and the original got only Unregister. ReactiveUI deactivates the old
view model before activating the new one; this follows that order.

ViewManager gains a protected OnLifecycle(TViewModel?, LifecycleEvent)
so a derived manager can address a view model the view no longer holds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

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.

Copilot review overview

🟡 Changes recommended

The public lifecycle documentation contradicts the new view-model replacement behavior.

Review effort: Balanced
Findings: 2 Low severity

Open (2)
What changed in this PR

Corrects lifecycle delivery when a parked MAUI row’s view model is replaced.

Changes:

  • Deactivates the originally activated view model.
  • Adds recycling lifecycle regression tests.
  • Includes stacked recycling, test setup, and documentation updates.
File Description
Stellar/​ViewManager.cs Adds targeted lifecycle dispatch.
Stellar.Maui/​MauiViewManager.cs Corrects parked-row deactivation.
Stellar.Maui/​Extensions/​ItemsViewExtensions.cs Avoids watchers for zero limits.
Stellar.Maui.UnitTests/​StellarTestBase.cs Documents shared ReactiveUI initialization.
Stellar.Maui.UnitTests/​MauiTestBase.cs Uses shared test initialization.
Stellar.Maui.UnitTests/​ItemsViewRecyclingTests.cs Adds recycling regression coverage.
README.md Documents retained recycled rows.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread README.md
Comment on lines +530 to +533
A kept row does **not** run `Bind`, `Initialized`, `Activated` or `Deactivated` again when it
is given its next item; it only receives `Detached` and `Attached`, and its view model's
item changes. Opt in only for rows that take everything they show from bindings to the view
model. A row that reads its item imperatively inside `Bind` would show the previous item.
}

// The view was given another view model while it was recycled. The one it was
// parked with is the one that was activated, so Deactivated is its to receive. The
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants