A behavior to animate mirroring of GUI elements on Windows Phone

3 minute read

imageIn this third and final installment of my scaling and opacity animation series I am going to show how easy it is to build more behaviors on top of the now existing framework I wrote about in my earlier post about extension methods for animating scales and opacity and the post after that, which showed a behavior to animate folding in and out a GUI element.

Building on top of the extension methods from the first post and the BaseScaleBehavior of the second post, I made a second behavior called MirrorBehavior. In Blend, it’s property panel looks like the identical twin of UnfoldBehavior. Which is not a coincidence, as it all the properties are in it’s base class.

It’s use case is very simple: suppose you have the completely hypothetical *cough* situation that you have created a game with the controls on the bottom of the screen or near the side of the screen – anyway, very near the back, start and search buttons of the phone. In the heat of the game they regularly strike one of those buttons – end of game. It would be nice to be able to get the controls out of the way.  You can let people rotate the phone, but ‘’upside down” is not supported. So you have the choice of giving your users an option to either rotate or mirror the playing field. This is exactly what I ran into during the building of my last game – of which I am very happy to say that it has passed certification this morning and is now sitting hidden in the Store while it’s availability is being propagated to the various servers. I took the latter approach – mirroring - and this is what happening in this space invaders ‘game as well.

Like I said, this behavior has exactly the same properties as Unfoldbehavior. If “Activated” is true, the object to which the behavior is attached will be mirrored, if its false it is displayed normally. The rest of the properties has the same meaning as in Unfoldbehavior, so see that article for more explanation. How this behavior’s effect work out is displayed in this video.

MirrorBehavior in action

As you see you can also mirror horizontal and vertical at the same time, but that doesn’t make as much sense – the effect isn’t very pretty. The red background is to show the background is staying where it it – just the element (the image) to which the behavior is attached changes.

And like Unfoldbehavior, only the two abstract methods BuildTransform and BuildStoryBoard need to be filled in. Since all the heavy lifting is already done in the previous two posts, all that remains to be written is this code:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Wp7nl.Utilities;

namespace Wp7nl.Behaviors
  /// <summary>
  /// Behaviors that mirrors an object via using an animation
  /// </summary>
  public class MirrorBehavior : BaseScaleBehavior
    protected override CompositeTransform BuildTransform()
      return new CompositeTransform
        ScaleX = (Direction == Direction.Horizontal || Direction == Direction.Both) && 
                  Activated ? -1 : 1,
        ScaleY = (Direction == Direction.Vertical || Direction == Direction.Both) && 
                  Activated ? -1 : 1

    protected override Storyboard BuildStoryBoard()
      var storyboard = new Storyboard {FillBehavior = FillBehavior.HoldEnd};
      var transform = BuildTransform();
      var duration = new Duration(TimeSpan.FromMilliseconds(Duration));
        AssociatedObject.GetScaleXProperty(), transform.ScaleX,
        AssociatedObject.GetScaleYProperty(), transform.ScaleY,
      return storyboard;

BuildTransform is nearly the same – only Activated is not negated, and the values runs from –1 to 1 in stead from 0 to 1. That’s the only trick involved – scaling to –1 ín XAML mirrors an object. Life can be so simple. BuildStoryBoard is even more the same as in UnfoldBehavior, only it now only animates the scale, and not the opacity.

That is all there is to it this time. Stay tuned for my game using this code – and ore that I still have to blog about - which is scheduled for release on Friday August 23, 8pm (or 20:00) CET.

Demo solution, as always, can be found here.