Custom Behaviors in Silverlight 3 and Blend 3

I’ve been spending a lot of time in Expression Blend lately. I wasn’t a huge fan of Blend 2, but Blend 3 is something I can get excited about. And one of the things that excites me is the ability to write custom behaviors.

Behaviors are pieces of code that a designer can attach to an object simply by dragging and dropping. Blend has a handful behaviors built in, including MouseDragElementBehavior, which you can attach to a UI element to allow it to be dragged with the mouse. Many more behaviors can be downloaded from the Expression Gallery’s Behaviors page, and you can write behaviors of your own. They tend to be simple to write, and they do a lot to enhance the power of Expression Blend–and Silverlight, too, for that matter.

The motivation for adding behaviors to Blend 3 was twofold. First, behaviors allow designers to add interactivity to scenes without writing any code. Second, behaviors help close the gap between Silverlight and WPF. In WPF, for example, you can add mouse-overs to objects in a scene declaratively. In Silverlight, you still have to write code. Or at least you did until behaviors came along. The code is still there, but it’s abstracted away so that a designer doesn’t have to write it or understand it.

A behavior is little more than a class that derives from Behavior or Behavior<T>, both of which are implemented in System.Windows.Interactivity.dll.To demonstrate, I built a custom behavior named BubblingMouseOverBehavior, which causes the object to which it’s attached to “bubble”–that is, increase in size–when the mouse cursor passes over it, and to revert to normal size when the mouse leaves. BubblingMouseOverBehavior exposes a dependency property named ScaleFactor that lets a designer specify how much the size of the object increases when a mouseover occurs. The default is 1.2, but you can set it to whatever you like.

To build BubblingMouseOverBehavior, I first added a reference to System.Windows.Interactivity.dll to my Silverlight project. Then I added a class named BubblingMouseOverBehavior to the project. Here’s the source code:

public class BubblingMouseOverBehavior : Behavior<UIElement>

{

    private Storyboard _sb;

    private DoubleAnimation _dax, _day;

    private ScaleTransform _st;

 

    public static readonly DependencyProperty ScaleFactorProperty =

        DependencyProperty.Register(“ScaleFactor”,

        typeof(double), typeof(BubblingMouseOverBehavior),

        new PropertyMetadata(1.2));

 

    public double ScaleFactor

    {

        get { return (double)GetValue(ScaleFactorProperty); }

        set { SetValue(ScaleFactorProperty, value); }

    }

       

    protected override void OnAttached()

    {

        base.OnAttached();

 

        // Register event handlers

        AssociatedObject.MouseEnter +=

            new MouseEventHandler(OnMouseEnter);

        AssociatedObject.MouseLeave +=

            new MouseEventHandler(OnMouseLeave);

 

        // Create ScaleTransform

        _st = new ScaleTransform();

        AssociatedObject.RenderTransformOrigin = new Point (0.5, 0.5);

 

        // Attach ScaleTransform to object

        if (AssociatedObject.RenderTransform == null)

        {

            AssociatedObject.RenderTransform = _st;

        }

        else

        {

            if (AssociatedObject.RenderTransform is TransformGroup)

            {

 ((TransformGroup)AssociatedObject.RenderTransform).Children.Add(_st);

            }

            else

            {

                TransformGroup group = new TransformGroup();

                group.Children.Add(AssociatedObject.RenderTransform);

                group.Children.Add(_st);

                AssociatedObject.RenderTransform = group;

            }

        }

 

        // Create Storyboard and animations

        _dax = new DoubleAnimation();

        _day = new DoubleAnimation();

        _dax.Duration = _day.Duration =

            new Duration(new TimeSpan(0, 0, 0, 0, 150));

 

        Storyboard.SetTarget(_dax, _st);

        Storyboard.SetTarget(_day, _st);

 

        Storyboard.SetTargetProperty(_dax, new PropertyPath(“ScaleX”));

        Storyboard.SetTargetProperty(_day, new PropertyPath(“ScaleY”));

 

        _sb = new Storyboard();

        _sb.Children.Add(_dax);

        _sb.Children.Add(_day);

    }

 

    protected override void OnDetaching()

    {

        base.OnDetaching();

 

        // Deregister event handlers

        AssociatedObject.MouseEnter -= new MouseEventHandler(OnMouseEnter);

        AssociatedObject.MouseLeave -= new MouseEventHandler(OnMouseLeave);

 

        // Remove ScaleTransform

        if (AssociatedObject.RenderTransform == _st)

        {

            AssociatedObject.RenderTransform = null;

        }

        else if (AssociatedObject.RenderTransform is TransformGroup)

        {

            TransformGroup group = (TransformGroup)AssociatedObject.RenderTransform;

            group.Children.Remove(_st);

        }

<

p class=”MsoNormal”>    }

 

    void OnMouseEnter(object sender, MouseEventArgs e)

    {

        _dax.To = _day.To = ScaleFactor;

        _sb.Begin();

    }

 

    void OnMouseLeave(object sender, MouseEventArgs e)

    {

        _dax.To = _day.To = 1.0;

        _sb.Begin();

    }

}

The key to a custom behavior is the virtual OnAttached method, which is called when an instance of the behavior is attached to an object. That’s where you wire up event handlers or do anything else you need to do to initialize the behavior. BubblingMouseOverBehavior’s OnAttached method registers handlers for MouseEnter and MouseLeave events. It also attaches a ScaleAnimation to the object it’s attached to, taking care not to disrupt any existing transforms attached to the object, and creates a Storyboard and a pair of DoubleAnimations to animate the ScaleTransform’s ScaleX and ScaleY properties.

If you open the project in Blend, BubblingMouseOverBehavior shows up in the list of behaviors. If you draw a rectangle and attach a BubblingMouseOverBehavior to it, Blend does something like this:

<Rectangle Width=”200″ Height=”100″ Fill=”Red” Margin=”0,0,0,20″ >

  <i:Interaction.Behaviors>

    <local:BubblingMouseOverBehavior />

  </i:Interaction.Behaviors>

</Rectangle>

Now if you run the project and pass the mouse over the rectangle, it bubbles up when the mouse enters the rectangle and back down when it leaves.

Behaviors open up a whole new playing field for Silverlight developers. Look for lots and lots of cool behaviors to be published to make adding interactivity to Silverlight apps easier than ever before. 

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X