Skip to content

Keep routed window-close triggers active through closure - #361

Merged
wieslawsoltes merged 2 commits into
masterfrom
agent/337-window-closed-routed-event
Aug 18, 2026
Merged

wieslawsoltes merged 2 commits into
masterfrom
agent/337-window-closed-routed-event

Conversation

@wieslawsoltes

Copy link
Copy Markdown
Owner

Summary

Allows a RoutedEventTriggerBehavior attached directly to a window to receive Window.WindowClosedEvent and execute actions whose bindings come from the window data context.

Root cause

Window shutdown crosses three distinct lifecycle points:

  1. the window leaves the visual/logical tree;
  2. WindowClosedEvent is raised;
  3. behavior resources can be released.

The previous implementation treated step 1 as the end of the behavior lifetime:

  • RoutedEventTriggerBehavior.OnDetachedFromVisualTree removed the routed handler;
  • getter-created behavior collections detached immediately;
  • StyledElementBehavior removed the behavior/action logical parent, clearing the bound InvokeCommandAction.Command.

As a result, simply retaining the routed handler was not enough: the event could be observed, but the command binding had already been torn down.

Changes

  • For a trigger attached directly to a TopLevel whose resolved event source is also a TopLevel:
    • retain the routed handler across visual detachment;
    • execute a routed event that arrives during that closing interval;
    • remove the handler after that post-detach event or on actual behavior detachment.
  • Keep ordinary control triggers tied to their existing visual-tree lifetime.
  • Preserve a top-level behavior's logical parent and action bindings through the closing event.
  • Defer getter-created top-level collection detachment by one dispatcher turn:
    • this lets the synchronous closed event complete first;
    • the collection is then detached if the same top-level/collection has not reattached or been replaced.
  • Document the supported window-close pattern.

Tests

Exact issue regression

A compiled-XAML headless window uses:

<RoutedEventTriggerBehavior RoutedEvent="{x:Static Window.WindowClosedEvent}">
  <InvokeCommandAction Command="{Binding CloseCommand}" />
</RoutedEventTriggerBehavior>

The test verifies:

  • the routed action runs exactly once;
  • the compiled bound command runs exactly once;
  • the behavior is detached after the closing event;
  • raising the event again cannot execute either action.

Lifecycle safeguards

Additional coverage verifies:

  • an ordinary control trigger unsubscribes when its control leaves the visual tree;
  • a top-level styled behavior retains its logical parent during the closing interval;
  • deferred detachment subsequently clears both the associated object and logical parent.

Validation:

  • dotnet test tests/Xaml.Behaviors.Interactivity.UnitTests/Xaml.Behaviors.Interactivity.UnitTests.csproj --no-restore
    • 94 passed, 0 failed
  • dotnet test tests/Xaml.Behaviors.Interactions.UnitTests/Xaml.Behaviors.Interactions.UnitTests.csproj --no-restore
    • 91 passed, 2 existing drag tests skipped, 0 failed

Closes #337

@wieslawsoltes
wieslawsoltes marked this pull request as ready for review July 14, 2026 22:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2318f282e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@wieslawsoltes
wieslawsoltes merged commit e1dee78 into master Aug 18, 2026
3 checks passed
@wieslawsoltes
wieslawsoltes deleted the agent/337-window-closed-routed-event branch August 18, 2026 08:59
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.

RoutedEventTriggerBehavior fails to trigger on window close

1 participant