Using Attached Events to Trigger Animations in WPF

This is a pattern I applied when implementing the WPF NotifyIcon component in order to provide animation support for popups, tooltips, and balloon messages. The problem I had to solve was the loose coupling between the NotifyIcon and displayed controls:

Accordingly, I didn’t know anything about these controls at runtime. Nonetheless, I wanted to provide a communication channel to inform that UIElement that it is being displayed. And I wanted to do it declaratively.

Attached Events to the Rescue

Enter attached events. Just like the better known attached properties, they can be declared in a static class and attached to arbitrary dependency objects. Accordingly, a control X does not need to declare an event itself in order to raise it.

If you are working with Expression Blend, chances are high that you are already using attached events quite often. As an example, the Mouse.MouseDown attached event that lets you trigger an animation if the user clicks on an arbitrary control. And nothing stops you from defining your own custom events 🙂

Creating a Sample Application

Let’s create a simple sample. The scenario is the following:

Sometimes, some kind of critical event occurs (simulated through a button click).

Every time this happens, we want a “status control” to show an alarm.

We will implement this status control purely in XAML – an attached event will trigger an animation that displays a warning sign:

(For a real-life usage scenario, have a look at the sample application that comes with the WPF NotifyIcon control.)

Preparing the Status Control

The control below is pretty simple. It just contains two images:

The regular image shows a star. Its initial opacity is set to 100%.

The second image is the alarm icon. Its initial opacity is set to 0% so it’s not visible (I changed that a little for the screenshot).

Defining the Attached Routed Event

In order to work with a custom event, it needs to be declared first. In the NotifyIcon library, the NotifyIcon control itself exposes the event. In this sample, however, we will declare an Alarm event in its own class called Monitor. Note that everything is static:

BTW: I didn’t write the code above on my own – code snippets greatly simplify things here. I’ve used one of Dr. WPF’s snippets which will not only generate the event declarations but also some helper methods to deal with events in code.

Raising the Event

The screenshot below shows a simple form that contains a button and the StatusRenderer user control. In order to keep things simple, we will simply raise the attached routed event on the status control every time the user clicks on the button.

In order to trigger the event, we’ll add a simple static helper method to the Monitor class:

Consuming the Event

The nice thing is – once the event is in place, it can be consumed through XAML only, so there’ no need to write code. Lets complete the sample by adding a simple listener to our user control that triggers an animation. I’m using Blend for that job.

1: Create a new event trigger

Start by clicking on the + Event tab in Blend. You will see that the Monitor.Alarm event is not available through this list. Accordingly, we will just use the Loaded event that is offered for now…

2. Create a storyboard to animate the UI

Next, click on the + button to create a new storyboard. For the sample application, I created a storyboard called ShowWarning that fades in the invisible warning sign and hides the default image.

3: Switch to the Monitor.Alarm event

In the first step, we registered our animation to be triggered whenever the user control’s Loaded event fires. However, we want our animation to be fired upon the attached Monitor.Alarm event. As Blend does not provide attached events through its UI, this needs to be changed XAML. Switch to XAML view and find the following line part.

I am writting a MVVM application where the XAML “View” is decoupled from the C# “ViewModel” (Not codebehind). There can be several instances of the same page each DataBound to thier own instance of the “ViewModel”, thus several instance of the same ViewModel class will exist – so it can not be static.

I wish to trigger a Story Board (in the “View”) from code in “ViewModel”. But trying to use your approach above I get stuck at the equivilent of this line:

Monitor.RaiseAlarmEvent(status)

This works for you because it is in Code Behind and you have a reference to the “status” Element:

For me I am trying to raise the event from the seperate “ViewModel” class with no reference to such Elements in the “View” (and I am not sure what element I would choose anyway).

Can you suggest a way I can programatically trigger a story board from my “ViewModel” Class ??

Please see my responses and questions after >>>>> below <<<<>>>> I am actually not sure what you mean by “submitting the View to the VM through a command” <<<<>>>> I do databind to Fields in the ViewModel. I also defined ICommands in my ViewModel which I data bind the Command attribute of various WPF element to. This allows me to connect from the XAML View “TO” the C# View model to access and display data and execute commands. It does not seem so easy to initiate the communication in the reverse direction from the ViewModel back to the View. In my case I wish to add code to a timer tick event handler in the ViewModel so that each time the timer ticks the Animation is started. <<<<>>>> Thanks but no that would not work – I am wanting a timer tick event handler in the ViewModel to initiate the Animation rather than a button. <<<<>>>> Thanks again Philipp Terry

Great example – thanks. It works for me, however when I select the Alarm trigger in Blend, it immediately disappears from the list (I am using Blend v4). I’m guessing this is a bug with Blend? I have a custom button (User control) that “clicks” when a user hovers using Kinect – I want the designers to be able to hook up animations without having to call me to do some c# every 5 minutes. Any suggestions?

Have you ever considered writing an e-book or guest authoring on other websites?

I have a blog centered on the same subjects you discuss and would really like
to have you share some stories/information. I know my visitors would
value your work. If you’re even remotely interested, feel free to shoot me an e mail.