dotnet/wpf · error · InvalidOperationException
SR.StyleTriggersCannotTargetTheTemplate
Error message
SR.StyleTriggersCannotTargetTheTemplate
What it means
Style-level triggers (PropertyTrigger/VisualTrigger in Style.Triggers) may only act on the container element itself; a trigger's PropertyValues may not target a named child (ChildName != SelfName). Template targeting is reserved for triggers inside a ControlTemplate, so ProcessVisualTriggers throws InvalidOperationException (SR.StyleTriggersCannotTargetTheTemplate).
Solutions
- Ensure every property value in the trigger has ChildName = StyleHelper.SelfName (no child targeting).
- Move child-targeting triggers into the ControlTemplate where the named child exists.
- Rebuild triggers for style use with plain property conditions only.
Example fix
// before
var trigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true };
trigger.Setters.Add(new Setter(TextBlock.ForegroundProperty, Brushes.Red) /* child-targeted pv */);
style.Triggers.Add(trigger); // throws if propertyValue.ChildName != SelfName
// after
var trigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true };
trigger.Setters.Add(new Setter(Control.ForegroundProperty, Brushes.Red)); // container-only
style.Triggers.Add(trigger); Defensive patterns
Strategy: validation
Validate before calling
foreach (var t in style.Triggers.OfType<TriggerBase>())
foreach (PropertyValue pv in /* trigger property values */ Enumerable.Empty<PropertyValue>())
if (pv.ChildName != StyleHelper.SelfName)
throw new InvalidOperationException("Style trigger targets a template child."); Type guard
static bool StyleTriggerIsContainerOnly(Trigger t) => t.Setters.OfType<Setter>().All(s => s.TargetName == null);
Try / catch
try { style.Seal(); }
catch (InvalidOperationException ex) { log.Error("Style trigger targets template", ex); } Prevention
- Keep template-targeting triggers inside the ControlTemplate where the named child exists.
- Never share Trigger instances between templates and styles.
- Use container-scoped properties (self) for style trigger conditions and setters.
When it happens
Trigger: A style MultiTrigger/Trigger whose Setter or condition is associated with a ChildName (from a template-derived or hand-built trigger) added to Style.Triggers, then sealed via Seal().
Common situations: Programmatically constructing Trigger objects reused between templates and styles; XAML tooling or code-gen emitting template-style triggers into Style.Triggers; deserialized triggers retaining ChildName data.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SR.Format(SR.TriggerOnStyleNotAllowedToHaveSource…
- SR.Format(SR.UnsupportedTriggerInStyle…
- Decorator marked as PART_ContentHost must have no content.
- InvalidOperationException (no message)
- Only Decorator and ScrollViewer can be used as…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/1b4650f2de1be4f4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Style.cs:734
if (style._visualTriggers != null)
{
// Merge in "self" and child TriggerBase PropertyValues while walking
// back up the tree. "Based-on" style rules are always added first
// (lower priority)
int triggerCount = style._visualTriggers.Count;
for (int i = 0; i < triggerCount; i++)
{
TriggerBase trigger = style._visualTriggers[i];
// Set things up to handle Setter values
for (int j = 0; j < trigger.PropertyValues.Count; j++)
{
PropertyValue propertyValue = trigger.PropertyValues[j];
// Check for trigger rules that act on container
if (propertyValue.ChildName != StyleHelper.SelfName)
{
throw new InvalidOperationException(SR.StyleTriggersCannotTargetTheTemplate);
}
TriggerCondition[] conditions = propertyValue.Conditions;
for (int k=0; k<conditions.Length; k++)
{
if( conditions[k].SourceName != StyleHelper.SelfName )
{
throw new InvalidOperationException(SR.Format(SR.TriggerOnStyleNotAllowedToHaveSource, conditions[k].SourceName));
}
}
// Track properties on the container that are being driven by
// the Style so that they can be invalidated during style changes
StyleHelper.AddContainerDependent(propertyValue.Property, true /*fromVisualTrigger*/, ref this.ContainerDependents);
StyleHelper.UpdateTables(ref propertyValue, ref ChildRecordFromChildIndex,
ref TriggerSourceRecordFromChildIndex, ref ResourceDependents, ref _dataTriggerRecordFromBinding,
null /*_childIndexFromChildID*/, ref _hasInstanceValues);View on GitHub (pinned to 81131a70a4)