dotnet/wpf · error · InvalidOperationException

SR.Format(SR.CannotHavePropertyInTemplate…

Error message

SR.Format(SR.CannotHavePropertyInTemplate, FrameworkElement.StyleProperty.Name)

What it means

Thrown by ControlTemplate.SealTemplate (via StyleHelper) when a template's visual triggers set the Style property on the templated container. A template cannot define the Style of its own container, since Style and Template are mutually determined; WPF forbids it to prevent infinite template resolution. The exception is an InvalidOperationException raised while sealing the template, i.e. when the template is first applied.

Solutions

  1. Remove the Setter that targets the Style property from the template's Triggers; set Style via the Style itself or on the control instance instead.
  2. If the intent was to restyle the template root element, give the root a named child (x:Name) and target the Setter with TargetName="...", or set properties directly.
  3. Replace the Style setter with individual property setters (e.g. Background, Foreground) inside the trigger.
  4. Verify which template triggers set container-dependent properties before applying the template; StyleHelper.IsSetOnContainer flags Style, DefaultStyleKey, OverridesDefaultStyle, and Name.

Example fix

<!-- before -->
<ControlTemplate TargetType="Button">
  <ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Style" Value="{StaticResource HoverStyle}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- after -->
<ControlTemplate TargetType="Button">
  <ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Background" Value="LightBlue"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>
Defensive patterns

Strategy: validation

Validate before calling

bool templateSetsContainerStyle(ControlTemplate t) =>
    t.Triggers.Cast<TriggerBase>().SelectMany(tr => tr is MultiTrigger mt ? mt.Setters : tr.Setters.Cast<SetterBase>())
     .OfType<Setter>().Any(s => s.Property == FrameworkElement.StyleProperty);

Try / catch

try { element.Template = template; element.ApplyTemplate(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Style"))
{
    // log template name; strip offending container setters before retrying
}

Prevention

When it happens

Trigger: Defining a ControlTemplate (or FrameworkTemplate) whose Trigger, MultiTrigger, or TriggerBase setters contain a Setter with Property="Style" targeting the container (TargetName omitted or set to the template root that maps to the container dependent property list). The error surfaces at template seal time — typically when the template is applied to a control.

Common situations: Copy-pasting a style trigger block into a template's <ControlTemplate.Triggers> and accidentally leaving a Setter for Style; tool-generated XAML that merges Style-level and template-level triggers; refactoring a Style so its Style setter drifted into the template triggers.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

            // 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.
            if (StyleHelper.IsSetOnContainer(FrameworkElement.OverridesDefaultStyleProperty, ref containerDependents, true))
            {
                throw new InvalidOperationException(SR.Format(SR.CannotHavePropertyInTemplate, FrameworkElement.OverridesDefaultStyleProperty.Name));
            }

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

View on GitHub (pinned to 81131a70a4)