Skip to content

Release the TextBlock text layout when the control is detached - #22281

Merged
Gillibald merged 1 commit into
AvaloniaUI:mainfrom
ronnycohen:fix/textblock-release-layout-on-detach
Oct 5, 2026
Merged

Gillibald merged 1 commit into
AvaloniaUI:mainfrom
ronnycohen:fix/textblock-release-layout-on-detach

Conversation

@ronnycohen

Copy link
Copy Markdown
Contributor

What does the pull request do?

TextBlock keeps its TextLayout alive after it has been detached from the visual tree, whenever the layout was built while the measure was already invalid.

What is the current behavior?

TextLayout is only released from OnMeasureInvalidated. InvalidateMeasure raises that override only while the measure is still valid, so once the measure has been invalidated the control holds its layout (and the native resources it owns) until the next measure pass.

A render pass reads TextBlock.TextLayout, which materializes the layout lazily. Reading it between an invalidation and the next measure pass therefore leaves the control holding a layout that nothing will release. If the control is then removed from the tree, the layout is never disposed.

What is the updated/expected behavior with this PR?

The layout is released when the control leaves the visual tree, regardless of the state of its measure. TextLayout is materialized lazily, so a control that is attached again rebuilds it on the next measure or render pass.

How was the solution implemented (if it's not obvious)?

OnDetachedFromVisualTree calls the existing DisposeTextLayout, which is unconditional.

Three tests were added:

  • Detaching_Should_Release_TextLayout the case that already passes today, kept so the two paths are visible side by side.
  • Detaching_Should_Release_TextLayout_Built_While_Measure_Is_Invalid the failing case. It is the only test in Avalonia.Controls.UnitTests that fails without the fix (1 of 3966).
  • Reattaching_Should_Rebuild_TextLayout a regression guard for disposing on detach. It passes with and without the fix; it is there to catch a control left blank after being reattached.

The tests observe the layout through a new internal bool HasTextLayout, following the existing internal bool HasComplexContent, rather than through reflection.

Checklist

Breaking changes

None

Obsoletions / Deprecations

None

Fixed issues

None

@MrJul MrJul added bug backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Sep 23, 2026
@github-actions

Copy link
Copy Markdown

NuGet packages

The packages for this pull request have been published (workflow run):

@Gillibald Gillibald 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.

LGTM

Thanks for the contribution

@Gillibald
Gillibald added this pull request to the merge queue Oct 5, 2026
Merged via the queue into AvaloniaUI:main with commit 6d993f5 Oct 5, 2026
12 checks passed
grokys pushed a commit to Evan260/Avalonia that referenced this pull request Oct 7, 2026
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants