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
- Delete any Setter/trigger that assigns the Template property from inside the template.
- Keep Template assignments at the Style level: wrap the template in <Style><Setter Property="Template"> instead.
- 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
- Never declare a Setter for Template/ContentPresenter.Template inside a ControlTemplate or DataTemplate.
- Set Template only at the Style level; swap looks with Background/other-property triggers.
- When refactoring a Style into a template, delete the Template setter — only the Setter.Value content becomes the template.
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
- SR.Format(SR.NullPropertyIllegal, "EventSetter.Event")
- SR.Format(SR.NullPropertyIllegal, "EventSetter.Handler")
- SR.Format(SR.NullPropertyIllegal, "Setter.Property")
- SR.Format(SR.UnexpectedParameterType, value.GetType()…
- SR.StylePropertyInStyleNotAllowed
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)