Behaviors : Writing Your Own Triggers
In my previous posts, I briefly discussed what behaviors are and how to use them. Let’s now talk about writing your own behaviors. Behaviors is a catch-all word that describes behaviors, actions, and extensible triggers. For an overview of what all three mean, check out Jeff Kelly’s blog post as well as Christian Schormann’s two overview blog posts on this topic.
Because there is already some great material out there on the basics of behaviors, I am going to shift gears and explain how to write behaviors. First up, I am going to go into some detail in this blog post by showing you how to write your own Trigger!
What are Triggers?
Like I mentioned earlier, behaviors (much like a famed group of musketeers!) are made up of three components – the Behavior, the Action, and the Trigger. The Trigger is really the catalyst for causing an Action and indirectly a Behavior to actually do something.
Examples of triggers range from something common such as an EventTrigger that fires an Action when a mouse or keyboard event is raised to something fun like a CollisionTrigger that fires an Action when two objects collide with each other. The thing to note is that, much like everything in our implementation of behaviors, Triggers are extensible. You can easily create your own kind of crazy triggers…such as what I am going to show you next.
The DoubleClick Trigger
One common gesture that I miss in Silverlight is the ability to double click. You can always click once, but if I want an Action to do something with a double click, I will have to provide this functionality myself. The below code shows you what a sample double click implementation looks like:
- namespace TriggerTest
- {
- public class DoubleClickTrigger : TriggerBase<UIElement>
- {
- private int count = 0;
- private DispatcherTimer _timer;
- public int DoubleClickSpeed
- {
- get { return (int)GetValue(DoubleClickSpeedProperty); }
- set { SetValue(DoubleClickSpeedProperty, value); }
- }
- public static readonly DependencyProperty DoubleClickSpeedProperty =DependencyProperty.Register(“DoubleClickSpeed”, typeof(int),typeof(DoubleClickTrigger), new PropertyMetadata(500,DoubleClickSpeedChanged));
- private static void DoubleClickSpeedChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
- {
- // Code for dealing with your property changes
- }
- protected override void OnAttached()
- {
- base.OnAttached();
- this.AssociatedObject.MouseLeftButtonDown += newMouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
- }
- void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgse)
- {
- if (count == 0)
- {
- _timer = new DispatcherTimer();
- _timer.Interval = new TimeSpan(0, 0, 0, 0, DoubleClickSpeed);
- _timer.Tick += new EventHandler(ResetCount);
- _timer.Start();
- }
- count++;
- if (count >= 2)
- {
- this.InvokeActions(null);
- }
- }
- void ResetCount(object sender, EventArgs e)
- {
- count = 0;
- _timer.Stop();
- }
- protected override void OnDetaching()
- {
- base.OnDetaching();
- this.AssociatedObject.MouseLeftButtonDown -= newMouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
- }
- }
When this trigger is used on an Action, double clicking on the element your Action is listening to will cause it to fire. I have a property called DoubleClickSpeed that allows you to adjust how quick or slow the double click needs to be before your two clicks are registered as a double click.
Looking Briefly at the Code
While it seems like a lot of code, what I am doing is actually pretty straightforward. Instead, I am going to remove all of the double click specific functionality and just show you the bare minimum of what you need to create a trigger:
- public class Trigger1 : TriggerBase<DependencyObject>
- {
- protected override void OnAttached()
- {
- base.OnAttached();
- }
- protected override void OnDetaching()
- {
- base.OnDetaching();
- }
- //
- // To invoke any associated Actions when this Trigger gets called, use
- // this.InvokeActions(o)
- //
- }
Notice that I am extending my class from TriggerBase – a type that is provided for you inside Microsoft.Expression.Interactivity.dll. Once I extend from the TriggerBase class, all I really have left to do is just override the OnAttached and OnDetaching methods like I show above.
Think of your OnAttached and OnDetaching methods like the constructor and destructor of your class. Anything you want initialized when the Trigger gets associated with an Action, be sure to specify it in the OnAttached method. Anything you want removed or cleaned up when the Trigger is no longer being associated with anything, be sure to put that in your OnDetaching method.
Finally, to actually have your trigger fire, though, you need to make a call to the InvokeActions method. Only when InvokeActions gets called will any Actions associated with this Trigger be notified to do whatever it is they do. My DoubleClickTrigger is simply an extension of the few lines of code that make up a barebones trigger starting point.
Using Triggers in Blend
Once you have written your trigger, using them in your own project is pretty straightforward. Draw a simple element, such as a rectangle, and drag and drop an Action on to it. If you don’t have any Actions you can use, feel free to borrow some from your peers on the Expression Gallery’s Behaviors category.
When you apply an Action to an element and select it, your Properties Inspector will display the current trigger applied as well as any properties your Action may expose. You can click the New button inside the Triggers category to display a dialog that allows you to pick your DoubleClickTrigger:

Once you have selected your DoubleClickTrigger, click OK to accept it as the Trigger for your Action. After you do that, your Trigger category will display the things relevant to you customizing your DoubleClickTrigger:

Well, that is all there is to it. Hopefully this post gave you a quick overview of how to write your own Triggers for this extensible family we call Behaviors.
Update: Thanks to a comment from Bart, I made a simple change to the code.
Cheers!
Kirupa ![]()