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
- Remove the DefaultStyleKey setter from the template's triggers.
- Set DefaultStyleKey via DefaultStyleKeyProperty.OverrideMetadata in the control's static constructor instead.
- If per-state key switching is needed, swap the Template or Style on the control, not DefaultStyleKey inside a template.
- 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
- Override DefaultStyleKey only in the control's static constructor via OverrideMetadata
- Do not theme-switch by setting DefaultStyleKey from within templates
- Keep theme key management in Style/metadata, never in template triggers
- Review machine-converted XAML for leaked DefaultStyleKey setters
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
- SR.Format(SR.CannotHavePropertyInTemplate…
- SR.Format(SR.CannotHavePropertyInTemplate…
- SR.Format(SR.CannotHavePropertyInTemplate…
- SR.TemplateTargetTypeMismatch
- SR.TriggersSupportsEventTriggersOnly
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)