dotnet/wpf · error · InvalidOperationException

SR.Format(SR.UnsupportedTriggerInTemplate…

Error message

SR.Format(SR.UnsupportedTriggerInTemplate, triggerBase.GetType().Name)

What it means

ProcessTemplateTriggers iterates a ControlTemplate's Triggers and throws when the trigger is neither a Trigger, nor a MultiTrigger/DataTrigger usable with actions, i.e. a trigger type unsupported inside templates was supplied (most commonly an EventTrigger in a position the code path treats as a BaseValue trigger, or a custom TriggerBase).

Solutions

  1. Remove the unsupported trigger from ControlTemplate.Triggers or replace it with a supported Trigger/MultiTrigger
  2. Move EventTrigger logic out of the template into element.Triggers or style triggers
  3. For custom trigger behavior, implement a TriggerAction-free approach such as visual states or attached behavior
  4. Log triggerBase.GetType() in your validation pass to identify the offending type

Example fix

// before
<ControlTemplate.Triggers>
  <EventTrigger RoutedEvent="ButtonBase.Click"><BeginStoryboard/></EventTrigger>
</ControlTemplate.Triggers>
// after
<ControlTemplate.Triggers>
  <Trigger Property="IsMouseOver" Value="True">
    <Setter Property="Opacity" Value="0.8"/>
  </Trigger>
</ControlTemplate.Triggers>
Defensive patterns

Strategy: validation

Validate before calling

foreach (var t in template.Triggers)
    if (!(t is Trigger || t is MultiTrigger || t is DataTrigger))
        throw new InvalidOperationException(t.GetType().Name + " not supported in template triggers");

Type guard

bool TemplateTriggerSupported(TriggerBase t) => t is Trigger || t is MultiTrigger || t is DataTrigger;

Try / catch

try { fe.Template = template; } catch (InvalidOperationException ex) when (ex.Message.Contains("not supported")) { fe.Triggers.AddRange(template.Triggers); fe.Template = null; }

Prevention

When it happens

Trigger: Setting ControlTemplate.Triggers to a trigger type not in {Trigger, MultiTrigger, DataTrigger} — e.g. a hand-added EventTrigger that failed the earlier eventTrigger branch check, or a custom class derived from TriggerBase.

Common situations: Copying Style triggers into a template and leaving an EventTrigger in the collection; third-party libraries adding custom trigger types; refactoring a Style into a template without pruning trigger kinds.

Related errors


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

Appendix: source

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

                                    StyleHelper.AddPropertyTriggerWithAction( triggerBase, triggerCondition.Property, ref propertyTriggersWithActions );
                                }
                            }
                            else if( dataTrigger != null )
                            {
                                StyleHelper.AddDataTriggerWithAction( triggerBase, dataTrigger.Binding, ref dataTriggersWithActions );
                            }
                            else if( multiDataTrigger != null )
                            {
                                for( int k = 0; k < multiDataTrigger.Conditions.Count; k++ )
                                {
                                    Condition dataCondition = multiDataTrigger.Conditions[k];

                                    StyleHelper.AddDataTriggerWithAction( triggerBase, dataCondition.Binding, ref dataTriggersWithActions );
                                }
                            }
                            else
                            {
                                throw new InvalidOperationException(SR.Format(SR.UnsupportedTriggerInTemplate, triggerBase.GetType().Name));
                            }
                        }
                    }
                    else if( eventTrigger != null )
                    {
                        StyleHelper.ProcessEventTrigger(eventTrigger,
                                                        childIndexFromChildID,
                                                        ref triggerActions,
                                                        ref eventDependents,
                                                        templateRoot,
                                                        frameworkTemplate,
                                                        ref eventHandlersStore,
                                                        ref hasLoadedChangeHandler);
                    }
                    else
                    {
                        throw new InvalidOperationException(SR.Format(SR.UnsupportedTriggerInTemplate, triggerBase.GetType().Name));
                    }

View on GitHub (pinned to 81131a70a4)