dotnet/wpf · error · InvalidOperationException

SR.Format(SR.CannotHavePropertyInTemplate…

Error message

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

What it means

Thrown by ControlTemplate.SealTemplate when the template's visual triggers set DefaultStyleKey on the templated container. DefaultStyleKey decides which theme style a control looks up; setting it from within that very template is a circular dependency, so WPF rejects it with InvalidOperationException at seal time. The message names the offending property (DefaultStyleKey).

Solutions

  1. Remove the DefaultStyleKey setter from the template's triggers.
  2. Set DefaultStyleKey via DefaultStyleKeyProperty.OverrideMetadata in the control's static constructor instead.
  3. If per-state key switching is needed, swap the Template or Style on the control, not DefaultStyleKey inside a template.
  4. Audit templates with a check for the four forbidden container properties (Style, DefaultStyleKey, OverridesDefaultStyle, Name) before applying them.

Example fix

// before (template trigger)
<Setter Property="DefaultStyleKey" Value="{x:Static local:MyControl.AlternateKey}"/>

// after (control static constructor)
static MyControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl),
        new FrameworkPropertyMetadata(typeof(MyControl)));
}
Defensive patterns

Strategy: validation

Validate before calling

bool templateSetsDefaultStyleKey(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.DefaultStyleKeyProperty);

Try / catch

try { element.ApplyTemplate(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("DefaultStyleKey"))
{
    // strip the DefaultStyleKey setter and reapply
}

Prevention

When it happens

Trigger: A ControlTemplate.Triggers section containing a Setter with Property="DefaultStyleKey". Detected by StyleHelper.IsSetOnContainer during SealTemplate, i.e. the first time the template is sealed/applied.

Common situations: Custom control authors copying template trigger XAML from another control that manipulated theme keys; metadata-generated or machine-converted XAML carrying a DefaultStyleKey setter into template triggers; attempted runtime theming by swapping DefaultStyleKey inside a template.

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/8cad52f640f14337. Report an issue: GitHub.

Appendix: source

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

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

View on GitHub (pinned to 81131a70a4)