dotnet/wpf · error · InvalidOperationException

SR.Format(SR.CannotHavePropertyInTemplate…

Error message

SR.Format(SR.CannotHavePropertyInTemplate, Control.TemplateProperty.Name)

What it means

SealTemplate rejects a ControlTemplate/DataTemplate whose visual triggers (ContainerDependents) set the Template property (Control.TemplateProperty or ContentPresenter.TemplateProperty) on the container. A template cannot recursively set the Template property of the element it is a template for — that would be self-referential — so WPF throws InvalidOperationException when the template is sealed.

Solutions

  1. Delete any Setter/trigger that assigns the Template property from inside the template.
  2. Keep Template assignments at the Style level: wrap the template in <Style><Setter Property="Template"> instead.
  3. If conditional templates are needed, use a TemplateSelector or swap templates via a Style trigger outside the template.

Example fix

<!-- before: inside ControlTemplate.Triggers -->
<ControlTemplate TargetType="Button">
  <ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button"/>
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- after: change visual via style-level trigger, not Template setter -->
<Trigger Property="IsMouseOver" Value="True">
  <Setter Property="Background" Value="LightBlue"/>
</Trigger>
Defensive patterns

Strategy: validation

Validate before calling

bool templateSetsTemplate(ControlTemplate ct) =>
    ct.Triggers.OfType<Trigger>().Any(t =>
        t.Setters.OfType<Setter>().Any(s => s.Property == Control.TemplateProperty));

Type guard

bool isTemplateSelfContained(ControlTemplate ct) =>
    !ct.Triggers.OfType<Trigger>().Any(t =>
        t.Setters.OfType<Setter>().Any(s => s.Property == Control.TemplateProperty || s.Property == ContentPresenter.TemplateProperty));

Try / catch

try { element.ApplyTemplate(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Template")) {
    // remove Template setters from inside the template
}

Prevention

When it happens

Trigger: Calling Template.Seal() (implicitly at first use) while the template contains a Trigger or setter targeting Control.TemplateProperty / ContentPresenter.TemplateProperty, e.g. <Setter Property="Template"> inside a template's trigger or directly on the template's element tree.

Common situations: Copy-pasting a full <Style> body (including a Template setter) inside a ControlTemplate instead of a Style; nesting template declarations when converting a style into a template; tool-generated XAML that re-emits the Template setter inside the template.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/StyleHelper.cs:431

                ref frameworkTemplate.DataTriggersWithActions,
                ref hasHandler );

            frameworkTemplate.HasLoadedChangeHandler = hasHandler;

            frameworkTemplate.SetResourceReferenceState();

            // All done, seal self and call it a day.
            isSealed = true;

            // Remove thread affinity so it can be accessed across threads
            frameworkTemplate.DetachFromDispatcher();

            // Check if the template has the Template property set on the container via its visual triggers.
            // It is an error to specify the TemplateProperty in your own Template.
            if (StyleHelper.IsSetOnContainer(Control.TemplateProperty, ref containerDependents, true) ||
                StyleHelper.IsSetOnContainer(ContentPresenter.TemplateProperty, ref containerDependents, true))
            {
                throw new InvalidOperationException(SR.Format(SR.CannotHavePropertyInTemplate, Control.TemplateProperty.Name));
            }

            // Check if the template has the Style property set on the container via its visual triggers.
            // It is an error to specify the StyleProperty in your own Template.
            if (StyleHelper.IsSetOnContainer(FrameworkElement.StyleProperty, ref containerDependents, true))
            {
                throw new InvalidOperationException(SR.Format(SR.CannotHavePropertyInTemplate, FrameworkElement.StyleProperty.Name));
            }

            // Check if the template has the DefaultStyleKey property set on the container via its visual triggers.
            // It is an error to specify the DefaultStyleKeyProperty in your own Template.
            if (StyleHelper.IsSetOnContainer(FrameworkElement.DefaultStyleKeyProperty, ref containerDependents, true))
            {
                throw new InvalidOperationException(SR.Format(SR.CannotHavePropertyInTemplate, FrameworkElement.DefaultStyleKeyProperty.Name));
            }

            // Check if the template has the OverridesDefaultStyle property set on the container via its visual triggers.
            // It is an error to specify the OverridesDefaultStyleProperty in your own Template.

View on GitHub (pinned to 81131a70a4)