dotnet/wpf · error · InvalidOperationException

SR.TriggersSupportsEventTriggersOnly

Error message

SR.TriggersSupportsEventTriggersOnly

What it means

During trigger processing (StyleHelper.ProcessTriggerCollection), a trigger in a FrameworkTemplate's trigger collection is not an EventTrigger, so ProcessOneTrigger cannot attach its event handler and throws. Template triggers support only EventTrigger; property triggers belong in Style.Triggers.

Solutions

  1. Convert the trigger to an EventTrigger (only type allowed in ControlTemplate.Triggers).
  2. Move property/data triggers from the template into the Style's Triggers collection (Style.Triggers).
  3. Use VisualStateManager states inside the template instead of property triggers.

Example fix

<!-- before -->
<ControlTemplate>
  <ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">...</Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- after -->
<Style>
  <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">...</Trigger>
  </Style.Triggers>
</Style>
Defensive patterns

Strategy: validation

Validate before calling

foreach (var t in template.Triggers)
    if (t is not EventTrigger)
        throw new InvalidOperationException("ControlTemplate.Triggers supports only EventTrigger.");

Type guard

bool IsTemplateTrigger(TriggerBase t) => t is EventTrigger;

Try / catch

try { ApplyTemplate(el); }
catch (InvalidOperationException) { /* move non-event triggers into Style.Triggers */ }

Prevention

When it happens

Trigger: Placing a Trigger, MultiTrigger, or DataTrigger inside a ControlTemplate/FrameworkTemplate's Triggers collection, which is then processed when the template is instantiated.

Common situations: Copying trigger XAML from a Style into a ControlTemplate; believing ControlTemplate.Triggers accepts DataTrigger; tooling that emits generic trigger elements inside templates.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/EventTrigger.cs:321

            if( eventTrigger != null )
            {
                Debug.Assert( eventTrigger._routedEventHandler == null && eventTrigger._source == null);
                
                // PERF: Cache this result if it turns out we're doing a lot of lookups on the same name.
                eventTrigger._source = FrameworkElement.FindNamedFrameworkElement( triggersHost, eventTrigger.SourceName );

                // Create a statefull event delegate (which keeps a ref to the FE).
                EventTriggerSourceListener listener = new EventTriggerSourceListener( eventTrigger, triggersHost );


                // Store the RoutedEventHandler & target for use in DisconnectOneTrigger
                eventTrigger._routedEventHandler = new RoutedEventHandler(listener.Handler);
                eventTrigger._source.AddHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler,
                                                 false /* HandledEventsToo */ );
            }
            else
            {
                throw new InvalidOperationException(SR.TriggersSupportsEventTriggersOnly);
            }
        }

        ////////////////////////////////////////////////////////////////////////
        //
        // DisconnectAllTriggers
        //
        // Call DisconnectOneTrigger for each trigger in the Triggers collection.

        internal static void DisconnectAllTriggers( FrameworkElement triggersHost )
        {
            TriggerCollection triggerCollection = TriggerCollectionField.GetValue(triggersHost);

            if( triggerCollection != null )
            {
                for( int i = 0; i < triggerCollection.Count; i++ )
                {
                    DisconnectOneTrigger( triggersHost, triggerCollection[i] );

View on GitHub (pinned to 81131a70a4)