Skip to content

TextView new-Text setter: guard flag not cleared in finally — throwing TextChanged subscriber permanently breaks polymorphic Text sync #5639

Closed

Description

@tig

Summary

In TextView's new Text property setter (TextView.Text.cs, ~lines 200–202 on the #5416 tree; pattern introduced with the #5371 Text CWP work), the _ownTextSetterActive-style guard flag is cleared outside a finally. A TextChanged subscriber that throws leaves the flag stuck true, permanently and silently disabling model sync for every later polymorphic set (((View) tv).Text = x).

Found during

v2.5.0 ecosystem validation (#5630). tui-cs/Editor mirrors TextView's pattern line-for-line; its review reproduced the failure test-first (Text_Set_Survives_Throwing_TextChanged_Subscriber, failing then fixed with try/finally in tui-cs/Editor#287 commit 84c597a). TextView carries the identical unguarded shape and needs the same hardening.

Suggested fix

Wrap the raise in try/finally so the flag always clears. Port the Editor test.

Also worth documenting (2.5.0 migration docs, not bugs)

Two inherent limitations of the new Text hiding pattern that apps copying TextView should know:

  1. The base View.Text mirror goes stale as the user edits (by design — no per-keystroke O(N) sync). A base-reference get after editing returns the stale mirror; a base-reference set equal to the stale mirror silently no-ops via View.Text's equality guard without syncing the model. Guidance: treat base View.Text as a write-through mirror; read text through the derived property.
  2. Setting the same value through the new setter raises events, diverging from View.Text's documented same-value no-op.

Found by Claude (Fable 5) agents during the #5630 ecosystem-validation gate.

Activity

  1. added this to the v2.x milestone on Aug 23, 2026
  2. added a commit that references this issue on Aug 31, 2026
    48efa0c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions