Jeremy Davis
Jeremy Davis
Sitecore, C# and web development
Article printed from: https://blog.jermdavis.dev/posts/2026/wpf-manually-trigger-storyboard

Manually triggering a WPF animation

When you need to do it with code

Published 15 June 2026
.Net C# WPF ~3 min. read

I have a complicated relationship with WPF. When you know what you're doing, it's great for building desktop apps. It's much easier to handle scenarios like apps getting used across varying DPIs, or doing complex UI layouts. But there are a few bits of it which, when you don't know how to do them, aren't intuitive. I bumped into another one the other day: Needing to trigger an animation on-demand. And so I can remember this next time I need to do this, here's a quick write-up of one way to achieve it...

The scenario url copied!

What I needed was (in theory) fairly simple. I had a TextBox which was going to accept some user input for doing a search. But in the scenario where the program had an issue with that input (which is most likely "no matches found") I wanted it to "flash" red to indicate the code had tried and failed.

It turns out this needs two things, which each have a bunch of detail:

The XAML url copied!

In WPF, the way you construct an animation is to apply a Storyboard to your component. You can define these in the Style element of your control, or have them as shared resources. This didn't seem like a "shared" scenario, so inside the TextBox element you can add something like:

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}">
        <Style.Resources>
            <Storyboard x:Key="flashSearchAnimation" RepeatBehavior="1x">
                <ColorAnimation Storyboard.TargetProperty="(TextBox.Background).(SolidColorBrush.Color)" 
                                From="White" To="Red" AutoReverse="False" RepeatBehavior="1x" Duration="0:0:0.125"/>
                <ColorAnimation Storyboard.TargetProperty="(TextBox.Background).(SolidColorBrush.Color)" 
                                From="Red" To="White" AutoReverse="False" RepeatBehavior="1x" Duration="0:0:0.125"/>
            </Storyboard>
        </Style.Resources>
	 ...
    </Style>
</TextBox.Style>

					

That applies a style to the TextBox which contains a Storyboard. For this example, that's made up of two colour changes - from white to red, and then back from red to white. But you can have whatever changes you need there. These are set to happen once when the animation is triggered, and complete over a fraction of a second.

The TargetProperty here is a bit complicated, and - I'll be honest - came straight out of a search query as I had no idea how to correctly express the idea that the animation needed to change the "colour of the brush used ro the TextBox background". But StackOverflow still has some uses...

Next you need to tell the TextBox under what scenarios you want this animation to run. The "when the mouse enters" kind of automatic start is fairly well documented. But if you want to control it manually, there's less useful info about. To achieve it, you need to apply Triggers to the component:

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}">
        <Style.Resources>
            ... as above ...
        </Style.Resources>
        <Style.Triggers>
            <EventTrigger RoutedEvent="local:TheWindowClass.FlashSearch">
                <BeginStoryboard Storyboard="{StaticResource flashSearchAnimation}"/>
            </EventTrigger>
        </Style.Triggers>
    </Style>
</TextBox.Style>


					

An EventTrigger can be used to start the animation when a specific event is raised. Commonly that event might be "mouse moved into component" or similar, but here it needs to be something custom. So this trigger needs two things. The RoutedEvent property needs to specify the event on some class that this trigger can subscribe to. And there needs to be a BeginStoryboard element which says "trigger the storyboard we defined above".

We'll get to defining the event in a second, but note how the RoutedEvent property needs three parts. First it needs the right namespace. That gets defined in the root control of your XAML file (most likely a window) alongside binding all the namespaces for bits of WPF:

<Window x:Class="ExampleProject.TheWindowClass"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ExampleProject"
        ...
        ResizeMode="CanResizeWithGrip">

					

Secondly, it needs the name of the control the event is defined on - the Window in this example (which is the TheWindowClass name here). And then thirdly it needs the name of the event property, which is FlashSearch here.

We need to define that property next.

Defining the event url copied!

Declaring a custom event needs two things. First you have to register the existence of your custom event with the runtime:

public static readonly RoutedEvent FlashSearchEvent = EventManager.RegisterRoutedEvent(
    name: "FlashSearch",
    routingStrategy: RoutingStrategy.Direct,
    handlerType: typeof(RoutedEventHandler),
    ownerType: typeof(TheWindowClass));

					

There are three ways you can make events travel through the system. I've picked RoutingStrategy.Direct here because I want to trigger the event directly on the component in question. But if you need one event to affect multiple components you may want one of the other options available here, so the event can Bubble up the component tree, or Tunnel down through it.

The critical thing with this declaration though is that the ownerType property needs to match the class you mentioned in the WPF above for the EventTrigger and its RoutedEvent property. I didn't realise that first time around, and it took me some time to realise this is what was causing my code to fail.

And secondly you need to expose a C# event property to allow subscribing and unsubscribing from this custom event. And the name of this custom property also needs to match what's in your RoutedEvent property:

public event RoutedEventHandler FlashSearch
{
    add { this.AddHandler(FlashSearchEvent, value); }
    remove { this.RemoveHandler(FlashSearchEvent, value); }
}

					

This is fairly boilerplate - it just ensures that when someone does the equivalent of FlashSearch += someHandler then that handler gets passed over to the RoutedEvent definition above.

Overall the EventTrigger RoutedEvent property in the XAML is a little unintuitive to me - it's it's referring to a class (TheWindowClass) but an instance property (FlashSearch) which something you'd not normally write - but I guess this is being used for reflection internally, so it does end up bound to the instance. But however they achieve it, it does work.

Triggering it url copied!

So finally you need to fire off your event. At the relevant point in your code you can put:

var e = new RoutedEventArgs(FlashSearchEvent);
searchEdit.RaiseEvent(e);

					

To declare an instance of RoutedEventArgs (which specifies what event you're raising) you need to pass it the static RoutedEvent defined above.

Then you raise that event object against whatever object you need. As mentioned earlier, I wanted it raised directly against my TextBox, but you might raise it against the window or elsewhere if that suits your requirement. But in that circumstance, consider how the event propagates through the controls, as mentioned above.

And with that in place, the flashing will now work:

A flashing textbox, made with the WPF code above

Poor screen-cap, but success none the less.

↑ Back to top

Manually triggering a WPF animation