stride3d/stride · error · ArgumentException

Invalid '{templatePart.GetType().FullName}' TemplatePart typ

Error message

Invalid '{templatePart.GetType().FullName}' TemplatePart type. '{typeof(T).FullName}' expected.

What it means

This ArgumentException is thrown by CheckTemplatePart<T> when the fetched template part exists but is not assignable to T. WPF templates can bind a part with a different concrete type than expected (e.g. a ToggleButton where a Button was expected), and this guard turns that mismatch into a descriptive error naming both the actual and expected types. It returns null (does not throw) when templatePart itself is null.

Solutions

  1. Fix the control template so the part named PART_... has the type the code expects
  2. Change the generic argument T in CheckTemplatePart<T> to the actual type of the part (and adjust usage)
  3. Add a type check on the part before use, or use as-cast with a null fallback for graceful degradation

Example fix

// before
var button = this.CheckTemplatePart<Button>(GetTemplateChild("PART_Action"));
// after
var button = this.CheckTemplatePart<ToggleButton>(GetTemplateChild("PART_Action"));
Defensive patterns

Strategy: validation

Validate before calling

var part = GetTemplateChild("PART_Action");
if (part is not Button) throw new InvalidOperationException("PART_Action must be a Button"); // or fallback

Type guard

T GetTypedPart<T>(object part) where T : class => part as T; // returns null instead of throwing

Try / catch

try { return this.CheckTemplatePart<Button>(GetTemplateChild("PART_Action")); }
catch (ArgumentException ex) when (ex.ParamName == "templatePart") { // re-type the template or log and degrade
  return null; }

Prevention

When it happens

Trigger: Calling CheckTemplatePart<T>(part) where part came from FindName/Template.FindName inside a control template but its runtime type is not T, e.g. GetTemplateChild returned a Border but T is Button, usually after editing the control's default template or a derived style replaced a part.

Common situations: Custom control authors renaming or retyping template parts in Theme.xaml; third-party theme libraries overriding the default template with differently typed parts; version upgrades where a part's type changed.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Extensions/DependencyObjectExtensions.cs:195

                d => LogicalTreeHelper.GetChildren(d).Cast<DependencyObject>().Count(),
                (d, i) => LogicalTreeHelper.GetChildren(d).Cast<DependencyObject>().ElementAt(i));
        }

        /// <summary>
        /// Checks that the given dependency object, retrieved as a template part of the calling object using <see cref="FrameworkElement.GetTemplateChild(string)"/>,
        /// exists and matches the given type.
        /// </summary>
        /// <typeparam name="T">The type expected for the template part.</typeparam>
        /// <param name="templatePart">The template part to evaluate.</param>
        /// <returns>The given template part, cast into the proper type.</returns>
        public static T CheckTemplatePart<T>(DependencyObject templatePart) where T : DependencyObject
        {
            if (templatePart == null)
                return null;

            if (templatePart is T == false)
            {
                throw new ArgumentException($"Invalid '{templatePart.GetType().FullName}' TemplatePart type. '{typeof(T).FullName}' expected.");
            }

            return (T)templatePart;
        }

        #region Helper methods

        /// <summary>
        /// Find the first parent that match the given type.
        /// </summary>
        /// <typeparam name="T">Type of parent to find.</typeparam>
        /// <param name="source">Base node from where to start looking for parent.</param>
        /// <param name="getParentFunc">Function that provide the parent element.</param>
        /// <returns>Returns the retrieved parent, or null otherwise.</returns>
        [CanBeNull]
        private static T FindParentOfType<T>(DependencyObject source, [NotNull] Func<DependencyObject, DependencyObject> getParentFunc) where T : DependencyObject
        {
            if (source == null) throw new ArgumentNullException(nameof(source));

View on GitHub (pinned to 96fad776d2)