Binary Bob’s Blog

8
Jan

Promoting reuse using Behaviors: RotateRefreshBehavior

Posted By Bob Bartholomay under Silverlight.

I needed a UI Control that enables the user to refresh the current View. When the user clicks the control it rotates as feedback.

The quickest way to do this would be to switch to the animation workspace in Blend and create a new Storyboard, set a KeyFrame and dial in a RotateTransform using the Properties Panel. What you end up with is a Storyboard in the Resources section of your XAML. You could then call the Storyboard’s Begin() method in some event handler. You could make this Animation more reusable by placing it into its own XAML resource file and then bring it into your project via MergedResources.

An even better approach to promoting reuse (as well as design time use in Blend) is to encapsulate this functionality into a Behavior. This makes it available to designers in Blend where they can just drag it from the Assets Panel onto a control on the artboard. You can then adjust the Behavior’s properties in Blend (instead of editing the XAML resource) to suit your needs and your done.

You will need to weigh a few variables to decide if the time spent coding up the Behavior is worth it in relation to your expected reuse. Programatically coding up Animations is more work than visually doing it in Blend. If you do indeed decide to make a Behavior, it will be most reusable if you create it in its own Visual Studio project ( a Silverlight Class Library project) so it lands in a separate dll that you (or the designer) can easily reference and use in future projects.

Here’s the Behavior applied to a Button that uses an Image as its Content. Hover over and click it to see the refresh animation…

The XAML is uninteresting but here’s the Behavior code: – Cheers!

?View Code CSHARP
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
 
namespace RotateRefreshBehavior
{
    public class RotateRefreshBehavior : Behavior<UIElement>
    {
        private RotateTransform rt;
        private Storyboard sb;
        private Transform origRenderTransform;
 
 
        private TimeSpan rotate_duration = TimeSpan.FromSeconds(.2);               
        private double rotate_angle = 360;
        private RepeatBehavior rotate_repeat = new RepeatBehavior(1);
        private bool rotate_autoReverse = false;
 
        private TimeSpan hover_duration = TimeSpan.FromSeconds(.1); 
        private double hover_angle = 30;
        private RepeatBehavior hover_repeat = RepeatBehavior.Forever;
        private bool hover_autoReverse = true;
 
        #region get/set
        [Description("Number of degrees to rotate on Click")]
        public double RotateAngle
        {
            get { return rotate_angle; }
            set { rotate_angle = value; }
        }
 
        [Description("Time to complete the rotation on Click")]
        public TimeSpan RotateDuration
        {
            get { return rotate_duration; }
            set { rotate_duration = value; }
        }
 
        [Description("Number of times to rotate_repeat on Click (0 is none)")]
        public RepeatBehavior RotateRepeatBehavior
        {
            get { return rotate_repeat; }
            set { rotate_repeat = value; }
        }
 
        [Description("Reverse the rotation when completed on Click")]
        public bool RotateAutoReverse
        {
            get { return rotate_autoReverse; }
            set { rotate_autoReverse = value; }
        }
 
        [Description("Number of degrees to rotate on Hover")]
        public double HoverAngle
        {
            get { return hover_angle; }
            set { hover_angle = value; }
        }
 
        [Description("Time to complete the rotation on Hover")]
        public TimeSpan HoverDuration
        {
            get { return hover_duration; }
            set { hover_duration = value; }
        }
 
        [Description("Number of times to rotate_repeat on Hover (0 is none)")]
        public RepeatBehavior HoverRepeatBehavior
        {
            get { return hover_repeat; }
            set { hover_repeat = value; }
        }
 
        [Description("Reverse the rotation when completed on Hover")]
        public bool HoverAutoReverse
        {
            get { return hover_autoReverse; }
            set { hover_autoReverse = value; }
        }
        #endregion
 
        protected override void OnAttached()
        {
            base.OnAttached();
 
            origRenderTransform = AssociatedObject.RenderTransform;
 
            AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;
 
            AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
        }
 
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.RenderTransform = origRenderTransform;
 
            AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;
 
            AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
        }
 
        private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            rt = new RotateTransform();
            AssociatedObject.RenderTransform = rt;
            AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
 
            var da = new DoubleAnimation();
            da.To = rotate_angle;
            da.Duration = rotate_duration;
 
            sb = new Storyboard();
            sb.RepeatBehavior = RotateRepeatBehavior;
            sb.AutoReverse = RotateAutoReverse;
 
            sb.Children.Add(da);
 
            Storyboard.SetTarget(da, rt);
            Storyboard.SetTargetProperty(da, new PropertyPath(RotateTransform.AngleProperty));
 
            sb.Begin();
        }
 
        private void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
        {
            rt = new RotateTransform();
            AssociatedObject.RenderTransform = rt;
            AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
 
            var da = new DoubleAnimation();
            da.To = hover_angle;
            da.Duration = hover_duration;
 
            sb = new Storyboard();
            sb.RepeatBehavior = HoverRepeatBehavior;
            sb.AutoReverse = HoverAutoReverse;
 
            sb.Children.Add(da);
 
            Storyboard.SetTarget(da, rt);
            Storyboard.SetTargetProperty(da, new PropertyPath(RotateTransform.AngleProperty));
 
            sb.Begin();
        }
 
        private void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
        {
            if (sb != null)
                sb.Stop();
        }
 
    }
}

4 Responses to “Promoting reuse using Behaviors: RotateRefreshBehavior”

  1. Dew Drop – January 9, 2010 | Alvin Ashcraft's Morning Dew said:

    [...] Promoting reuse using Behaviors: RotateRefreshBehavior (Bob Bartholomay) [...]

  2. Links (1/10/2010) « Steve Pietrek-Everything SharePoint/Silverlight said:

    [...] Promoting reuse using Behaviors: RotateRefreshBehavior [...]

  3. Enlaces Interesantes Silverlight/WPF 11-01-2010 - Blog de Oskar Alvarez said:

    [...] Promoting reuse using Behaviors: RotateRefreshBehavior (Bob Bartholomay) [...]

  4. Binary Bob’s Blog » FlexibleBehavior class: More on reuse and Behaviors said:

    [...] recent post explained how encapsulating functionality (e.g. Animations, etc) into a Behavior promoted reuse in [...]

Leave a Reply