dotnet/wpf · error · NotSupportedException

SR.TextBoxScrollViewerMarkedAsTextBoxContentMustHaveNoConten…

Error message

SR.TextBoxScrollViewerMarkedAsTextBoxContentMustHaveNoContent

What it means

When TextBoxBase finds a ScrollViewer marked as its text-box content part (via template parts) whose Content is already set, it aborts attaching the internal render scope and throws NotSupportedException. A ScrollViewer designated as PART content host must have no other content, since TextBoxBase installs its own editing scope into it.

Solutions

  1. Remove all content from the ScrollViewer part in the template; host extra visuals in a sibling Grid overlay instead.
  2. Name the ScrollViewer part correctly (PART_ContentHost) and leave its Content empty so TextBoxBase can attach its render scope.
  3. Base custom templates on the default TextBox template and only modify styling, not the part structure.

Example fix

// before
<ScrollViewer x:Name="PART_ContentHost">
    <TextBlock Text="extra"/> <!-- content present -> throws -->
</ScrollViewer>
// after
<Grid>
    <ScrollViewer x:Name="PART_ContentHost"/>
    <TextBlock Text="extra" IsHitTestVisible="False"/>
</Grid>
Defensive patterns

Strategy: validation

Validate before calling

// In the template, before apply:
bool contentHostIsEmpty = scrollViewerPart.Content == null;
if (!contentHostEmpty) throw new InvalidOperationException("PART_ContentHost ScrollViewer must have no content");

Type guard

static bool IsValidTextBoxContentHost(ScrollViewer sv) => sv != null && sv.Content == null;

Try / catch

try
{
    textBox.Template = customTemplate;
    textBox.ApplyTemplate();
}
catch (NotSupportedException)
{
    textBox.Template = null; // revert to default template
}

Prevention

When it happens

Trigger: Applying a custom ControlTemplate for TextBox/TextBoxBase where the ScrollViewer part already contains child elements (x:Bind content, injected children, or leftover content from a modified template).

Common situations: Hand-edited or third-party TextBox templates that place extra visuals directly inside the content-host ScrollViewer instead of in an adorner/overlay layer; template upgrades between framework versions.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/b2e9304985fae97c. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TextBoxBase.cs:1901

            ClearContentHost();

            // Find ContentHostTemplateName in the style
            _textBoxContentHost = GetTemplateChild(ContentHostTemplateName) as FrameworkElement;
            // Note that we allow ContentHostTemplateName to be optional.
            // This simplifies toolability of our control styling.
            // When the ContentHostTemplateName is not found or incorrect
            // TextBox goes into disabled state, but not throw.

            // Add renderScope as a child of ContentHostTemplateName
            _renderScope = renderScope;
            if (_textBoxContentHost is ScrollViewer scrollViewer)
            {
                if (scrollViewer.Content != null)
                {
                    _renderScope = null;
                    _textBoxContentHost = null;
                    //  Do not throw exception
                    throw new NotSupportedException(SR.TextBoxScrollViewerMarkedAsTextBoxContentMustHaveNoContent);
                }
                else
                {
                    scrollViewer.Content = _renderScope; // this may replace old render scope in case of upgrade scenario in TextBox
                }
            }
            else if (_textBoxContentHost is Decorator decorator)
            {
                if (decorator.Child != null)
                {
                    _renderScope = null;
                    _textBoxContentHost = null;
                    //  Do not throw exception
                    throw new NotSupportedException(SR.TextBoxDecoratorMarkedAsTextBoxContentMustHaveNoContent);
                }
                else
                {
                    decorator.Child = _renderScope; // this may replace old render scope in case of upgrade scenario in TextBox

View on GitHub (pinned to 81131a70a4)