Skip to content

Preserve bound actions during detach triggers - #369

Merged
wieslawsoltes merged 2 commits into
masterfrom
agent/353-detached-trigger
Aug 19, 2026
Merged

wieslawsoltes merged 2 commits into
masterfrom
agent/353-detached-trigger

Conversation

@wieslawsoltes

Copy link
Copy Markdown
Owner

Summary

  • execute visual/logical detach callbacks before releasing behavior and action logical scope
  • keep bound detach-trigger commands valid during the callback
  • guarantee scope cleanup with try/finally, even when a custom callback throws
  • add the exact compiled-XAML TabControl regression and document detach semantics

Root cause

The recent synchronous action-logical-tree cleanup exposed an ordering problem in StyledElementBehavior:

  1. DetachedFromVisualTreeEventHandler detached the behavior/action logical tree
  2. command bindings and inherited data context were released
  3. DetachedFromVisualTreeTrigger.OnDetachedFromVisualTree executed its actions

The trigger itself still fired, but InvokeCommandAction.Command was already null. This made the reported bound method/command appear not to run when switching tabs.

The logical-tree detach path had the same ordering contract and is corrected alongside the visual path.

Changes

  • notify OnDetachedFromVisualTree before DetachBehaviorFromLogicalTree
  • notify OnDetachedFromLogicalTree before releasing the same scope
  • use try/finally so parent, templated-parent, action lifecycle, and command observer cleanup still run if a consumer callback throws
  • document that detach triggers retain their binding scope through callback execution

Tests

Reported regression

A compiled-XAML headless fixture mirrors the issue:

  • a TabControl hosts a TextBlock
  • the text block has DetachedFromVisualTreeTrigger
  • InvokeCommandAction.Command is compiled-bound from the window data context
  • switching tabs executes the bound command exactly once

The regression test fails on current master and passes with this change.

Cleanup safeguard

A behavior whose visual-detach callback throws verifies that logical parent and templated parent are still cleared.

Validation

  • focused detach/action-lifetime tests: 17 passed
  • focused behavior cleanup tests: 2 passed
  • Xaml.Behaviors.Interactivity.UnitTests: 94 passed
  • Xaml.Behaviors.Interactions.UnitTests: 90 passed, 2 pre-existing skipped
  • git diff --check: clean

Closes #353

@wieslawsoltes
wieslawsoltes merged commit 344de7c into master Aug 19, 2026
3 checks passed
@wieslawsoltes
wieslawsoltes deleted the agent/353-detached-trigger branch August 19, 2026 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DetachedFromVisualTreeTrigger not triggered in v12.0.5

1 participant