stride3d/stride · error · InvalidOperationException

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

Error message

A part named 'PART_LogTextBox' must be present in the ControlTemplate, and must be of type 'RichTextBox'.

What it means

TextLogViewer requires its ControlTemplate to declare a part named 'PART_LogTextBox' of type RichTextBox, which hosts the rendered log content. OnApplyTemplate retrieves the part and throws InvalidOperationException when it is absent or of the wrong type, since the control cannot display logs without it. Unlike PART_ClearLog (optional), this part is mandatory.

Solutions

  1. Add <RichTextBox x:Name="PART_LogTextBox"/> to the ControlTemplate for TextLogViewer.
  2. Make sure the part is exactly a RichTextBox (not TextBox or RichTextBox derived hosted in another name).
  3. Revert to the library's default template if you do not need custom visuals.
  4. Optionally include the optional <ButtonBase x:Name="PART_ClearLog"/> to keep the clear-log feature.

Example fix

// before
<ControlTemplate TargetType="controls:TextLogViewer">
  <TextBox x:Name="LogArea"/>
</ControlTemplate>
// after
<ControlTemplate TargetType="controls:TextLogViewer">
  <RichTextBox x:Name="PART_LogTextBox" IsReadOnly="True"/>
</ControlTemplate>
Defensive patterns

Strategy: validation

Validate before calling

var rtb = template.FindName("PART_LogTextBox", scope) as RichTextBox;
if (rtb == null) throw new InvalidOperationException("TextLogViewer template must contain RichTextBox named PART_LogTextBox");

Type guard

bool HasLogTextBoxPart(FrameworkElement scope) => scope.FindName("PART_LogTextBox", scope) is RichTextBox;

Try / catch

try { logViewer.ApplyTemplate(); } catch (InvalidOperationException ex) when (ex.Message.Contains("PART_LogTextBox")) { /* fall back to default template */ }

Prevention

When it happens

Trigger: Assigning a custom ControlTemplate to TextLogViewer without an element named 'PART_LogTextBox', or where 'PART_LogTextBox' resolves to a non-RichTextBox element. Also when the default template cannot be resolved at apply-template time.

Common situations: Re-templating the log viewer for branding; copying the template but dropping or renaming the log area; upgrading the library and stale templates in resource dictionaries referencing older part names.

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/5f15ff8d37fb62af. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Controls/TextLogViewer.cs:296

        /// <summary>
        /// Gets or sets whether the log viewer should display fatal messages.
        /// </summary>
        public bool ShowFatalMessages { get { return (bool)GetValue(ShowFatalMessagesProperty); } set { SetValue(ShowFatalMessagesProperty, value.Box()); } }

        /// <summary>
        /// Gets or sets whether the log viewer should display fatal messages.
        /// </summary>
        public bool ShowStacktrace { get { return (bool)GetValue(ShowStacktraceProperty); } set { SetValue(ShowStacktraceProperty, value.Box()); } }

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

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

            var clearLogButton = GetTemplateChild("PART_ClearLog") as ButtonBase;
            if (clearLogButton != null)
            {
                clearLogButton.Click += ClearLog;
            }

            var previousResultButton = GetTemplateChild("PART_PreviousResult") as ButtonBase;
            if (previousResultButton != null)
            {
                previousResultButton.Click += PreviousResultClicked;
            }
            var nextResultButton = GetTemplateChild("PART_NextResult") as ButtonBase;
            if (nextResultButton != null)
            {
                nextResultButton.Click += NextResultClicked;
            }

View on GitHub (pinned to 96fad776d2)