stride3d/stride · error · InvalidOperationException

A part named 'PART_ContentHost' must be present in the…

Error message

A part named 'PART_ContentHost' must be present in the ControlTemplate, and must be of type 'ScrollViewer'.

What it means

NumericTextBox.OnApplyTemplate requires a ScrollViewer named 'PART_ContentHost' that hosts the editable text. When the applied template lacks it or uses a different element type, GetTemplateChild returns null and an InvalidOperationException is thrown.

Solutions

  1. Add <ScrollViewer x:Name="PART_ContentHost"/> to the ControlTemplate (it must contain the text host)
  2. Keep the exact case-sensitive name PART_ContentHost
  3. Ensure the element is a ScrollViewer, not another container type
  4. Derive your template from the default NumericTextBox template

Example fix

<!-- before -->
<Grid>
  <TextBox x:Name="PART_ContentHost"/>
</Grid>
<!-- after -->
<Grid>
  <ScrollViewer x:Name="PART_ContentHost"/>
</Grid>
Defensive patterns

Strategy: validation

Validate before calling

var host = numericTextBox.Template?.FindName("PART_ContentHost", numericTextBox) as ScrollViewer;
if (host == null) throw new InvalidOperationException("NumericTextBox template missing PART_ContentHost (ScrollViewer)");

Type guard

bool HasContentHost(NumericTextBox c) => c.Template?.FindName("PART_ContentHost", c) is ScrollViewer;

Try / catch

try { control.ApplyTemplate(); }
catch (InvalidOperationException ex) { log.Error(ex, "Invalid NumericTextBox template; restoring default style"); control.Style = null; }

Prevention

When it happens

Trigger: Custom ControlTemplate for NumericTextBox without a ScrollViewer named PART_ContentHost; part renamed; replaced with a TextBox or ContentPresenter directly.

Common situations: Re-skinning numeric editors and omitting the content host; templates derived from plain TextBox styles that name the host differently; edits that convert the ScrollViewer into a Border.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/a8b53d1eda8e6c72. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Controls/NumericTextBox.cs:275

        /// </summary>
        public event EventHandler<RepeatButtonPressedRoutedEventArgs> RepeatButtonReleased { add { AddHandler(RepeatButtonReleasedEvent, value); } remove { RemoveHandler(RepeatButtonReleasedEvent, value); } }

        /// <inheritdoc/>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            increaseButton = GetTemplateChild("PART_IncreaseButton") as RepeatButton;
            if (increaseButton == null)
                throw new InvalidOperationException("A part named 'PART_IncreaseButton' must be present in the ControlTemplate, and must be of type 'RepeatButton'.");

            decreaseButton = GetTemplateChild("PART_DecreaseButton") as RepeatButton;
            if (decreaseButton == null)
                throw new InvalidOperationException("A part named 'PART_DecreaseButton' must be present in the ControlTemplate, and must be of type 'RepeatButton'.");

            contentHost = GetTemplateChild("PART_ContentHost") as ScrollViewer;
            if (contentHost == null)
                throw new InvalidOperationException("A part named 'PART_ContentHost' must be present in the ControlTemplate, and must be of type 'ScrollViewer'.");

            var increasePressedWatcher = new DependencyPropertyWatcher(increaseButton);
            increasePressedWatcher.RegisterValueChangedHandler(ButtonBase.IsPressedProperty, RepeatButtonIsPressedChanged);
            var decreasePressedWatcher = new DependencyPropertyWatcher(decreaseButton);
            decreasePressedWatcher.RegisterValueChangedHandler(ButtonBase.IsPressedProperty, RepeatButtonIsPressedChanged);
            var textValue = FormatValue(Value);

            SetCurrentValue(TextProperty, textValue);
        }

        /// <summary>
        /// Raised when the <see cref="Value"/> property has changed.
        /// </summary>
        protected virtual void OnValueChanged(double? oldValue, double? newValue)
        {
        }

        /// <inheritdoc/>

View on GitHub (pinned to 96fad776d2)