Behaviors : Writing Your Own Triggers
April 9th, 2009 | 8 Comments
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 += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
- }
- void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- 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 -= new MouseButtonEventHandler(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





April 10th, 2009 at 7:44 am
Nice article.
The code is not thread-safe here. Don’t mean to be a “threading troll”, but in this case you actually might have a problem as your reset method/increment could step over each other.
It wouldn’t break anything but probably the double click wouldn’t register or fire early. Maybe changing the line:
if (count == 2)
to
if (count >= 2)
this way if for some reason the Reset reset one click and not the previous then it wouldn’t seem to act weird and fire off on one click.
April 10th, 2009 at 12:36 pm
Hi Bart – thanks a lot for the feedback. I have updated the post with your change.
Cheers!
Kirupa
May 13th, 2009 at 3:15 pm
Wouldn’t it be simpler to just store off the time of the previous click instead of using a DispatchTimer? So the code would look something like this:
DateTime _lastClickTime = DateTime.Min;
void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TimeSpan timeSinceLastClick = DateTime.Now – _lastClickTime;
if (timeSinceLastClick <= DoubleClickSpeed)
{
this.InvokeActions(null);
}
}
Also correct me if I’m wrong but I wouldn’t think Thread Safety would be an issue, because the Trigger should always run on the UI Thread.
May 16th, 2009 at 10:46 am
Edgar – I changed it to use the timestamp approach shortly after I published my original one.
I agree that it is much simpler!
August 3rd, 2009 at 6:02 am
Help!
Hello is anyone here who kan help me?. Im having problems in linking my gallery made in flash to the rest of my homepage made in html…I have seen several examples of codes, about how to link from flash to a new URL, but I just need to link to a local html file…
So I have to questions.
First. Which are the codes to use in my flash buttom to link to a local html file, or another flash file?
And second.How relevant is the swf location?. I mean, I named my gallery: “galeria.html”(I have published my flash gallery in html). Does the swf file have to stay in the same directory than the gallery in order to kan display it in the browser?
Thanks a lot to whom take some time to read this.
And sorry if there is any spelling error. This is the first time I write some english, in many many years.
Regards,
Kelly
August 12th, 2009 at 8:41 am
Hello,
I am trying to write a custom behavior using SL3 and Blend3 but I am not getting very far.
public class DoubleClickTrigger : TriggerBase
{
}
Error:
error CS0308: The non-generic type ‘System.Windows.TriggerBase’ cannot be used with type arguments
I have referenced Microsoft.Expression.Interactions.dll but cannot find the Microsoft.Expression.Interactivity.dll mentioned in most samples. I suspect the final version of SL3 and/or Blend3 have changed things up a bit.
Any ideas?
Thanks,
Rick
August 18th, 2009 at 10:18 am
Rick – please add a reference to System.Windows.Interactivity instead. The samples and other documentation are out of date because we changed the assembly name before we released
Cheers!
Kirupa
February 4th, 2010 at 3:39 pm
Hello hunnie, great site! I genuinely appreciate this blog post.. I was wondering about this for a while now. This cleared a lot up for me! Do you have a rss feed that I can add?