[Windows Phone] Populating content smoothly

We, users of the Windows Phone OS, love its fluidity and how content is populated smoothly throughout the OS (take for example how album thumbnails are loaded in the Pictures Hub).

As developers, we don’t have any built-in mechanism to populate content this way, but we can fix that by using transitions, storyboards and behaviors. For this post, we will create two classes: OpacityTransition and OnLoadedOpacityBehavior.

First of all, we will need a custom implementation of the ITransition interface. This interface is exposed by the Silverlight for Windows Phone Toolkit. The implementation is pretty straightforward. We will have an instance of a StoryBoard passed in the constructor and will call its methods as needed in our implementation:

   1: public class CustomTransition : ITransition

   2: {

   3:     readonly Storyboard _storyboard;

   4:

   5:     public CustomTransition(Storyboard sb)

   6:     {

   7:         _storyboard = sb;

   8:     }

   9:

  10:     #region ITransition Members

  11:

  12:     public void Begin()

  13:     {

  14:         _storyboard.Begin();

  15:     }

  16:

  17:     public event EventHandler Completed

  18:     {

  19:         add

  20:         {

  21:             _storyboard.Completed += value;

  22:         }

  23:         remove

  24:         {

  25:             _storyboard.Completed -= value;

  26:         }

  27:     }

  28:

  29:     public ClockState GetCurrentState()

  30:     {

  31:         return _storyboard.GetCurrentState();

  32:     }

  33:

  34:     public TimeSpan GetCurrentTime()

  35:     {

  36:         throw new NotImplementedException();

  37:     }

  38:

  39:     public void Pause()

  40:     {

  41:         _storyboard.Pause();

  42:     }

  43:

  44:     public void Resume()

  45:     {

  46:         _storyboard.Resume();

  47:     }

  48:

  49:     public void Seek(TimeSpan offset)

  50:     {

  51:     }

  52:

  53:     public void SeekAlignedToLastTick(TimeSpan offset)

  54:     {

  55:     }

  56:

  57:     public void SkipToFill()

  58:     {

  59:         _storyboard.SkipToFill();

  60:     }

  61:

  62:     public void Stop()

  63:     {

  64:         _storyboard.Stop();

  65:     }

  66:

  67:     #endregion

  68: }

This CustomTransition will be the ITransition type required to be returned by the GetTransition method of the TransitionElement class. More on this now.

Let’s create the actual transition class that changes the Opacity property of any UIElement. The primary goal here is to display content with a subtle fade in effect. This class will inherit from TransitionElement, an abstract class found in the Microsoft.Phone.Controls.Toolkit assembly. This class just creates a StoryBoard, sets its target and return our CustomTransition with that StoryBoard:

   1: public class OpacityTransition : TransitionElement

   2:     {

   3:         public override ITransition GetTransition(UIElement element)

   4:         {

   5:             var myStoryboard = CreateStoryboard(0.0, 1.0);

   6:             Storyboard.SetTarget(myStoryboard, element);

   7:             return new CustomTransition(myStoryboard);

   8:         }

   9:

  10:         private Storyboard CreateStoryboard(double from, double to)

  11:         {

  12:             var sb = new Storyboard();

  13:

  14:             var animation = new DoubleAnimation();

  15:             animation.From = from;

  16:             animation.To = to;

  17:             var duration = new Duration(TimeSpan.FromSeconds(0.2));

  18:             animation.Duration = duration;

  19:             Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));

  20:             sb.Children.Add(animation);

  21:

  22:             return sb;

  23:         }

  24:     }

Now it’s time for the Behavior.Behaviors are attachable and reusable pieces of code which add interactivity to your application. Because of this, the following piece of interactivity we are going to implement can be reused in all your applications.

   1: public class OnLoadedOpacityTransitionBehavior : Behavior<FrameworkElement>

   2: {

   3:     protected override void OnAttached()

   4:     {

   5:         base.OnAttached();

   6:

   7:         AssociatedObject.Loaded += AssociatedObjectLoaded;

   8:     }

   9:

  10:     protected override void OnDetaching()

  11:     {

  12:         base.OnDetaching();

  13:

  14:         AssociatedObject.Loaded -= AssociatedObjectLoaded;

  15:     }

  16:

  17:     private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)

  18:     {

  19:         var opacityTransition = new OpacityTransition();

  20:         var transition = opacityTransition.GetTransition(sender as UIElement);

  21:         transition.Begin();

  22:     }

  23: }

The important part here is the subscription to the Loaded event. This means that every time the Loaded event is fired on a control, our behavior will do its magic and the content of that control will be displayed smoothly.

Finally, we need to declare this behavior in our XAML. We can do it individually for any control (TextBlock, Image, Button, etc.) or declare it in the container parent (Grid, StackPanel, etc.). The first option will make every individual control to be display smoothly as its Loaded event is fired. The second will animate all of them at once as the container Loaded event is fired. This is up to you and your application’s needs, but take into account that by using the first option, your application’s performance may decrease if there are many elements on screen.

   1: <Image Opacity="0.0" Source="{Binding Image}">

   2:     <i:Interaction.Behaviors>

   3:         <Behaviors:OnLoadedOpacityTransitionBehavior/>

   4:     </i:Interaction.Behaviors>

   5: </Image>

Note that the initial Opacity value of the control must be 0.0 (invisible). Our behavior will be responsible to animate the Opacity from 0.0 to 1.0 (visible) when the Loaded event is fired for this control.

And that’s all. Now you don’t have any excuse for not displaying list results, images or any other content of your application smoothly.

Hope it helps and happy coding!

Un comentario en “[Windows Phone] Populating content smoothly

  1. Pingback: [Windows Phone] Populating content smoothly

Deja un comentario