I’ve been meaning to write about this one for a while. AnimatingPanelBase is a substitute base class for Panel that makes it super easy to add motion to Panels in Silverlight. It works just like any other Panel. You define your layout logic in Measure and Arrange just like you normally would and you get the animation for free. I’ve got a couple of demos below.

We actually talked about this (and gave out the code) at our talk at MIX this year. That certainly does not make me the first kid on the block with an animated panel (that’s probably Kevin Moore), but it may be the most versatile.

HowitWorks

I use the same technique for animation that Kevin used and roughly the same technique that Dave Relyea describes here. (By the way, I have chosen to view that as an official endorsement of this technique from the Silverlight team. Sorry guys, it’s official now.)

The basic idea is that you create a timer (either using DispatcherTimer or a 0-Second Storyboard) and then update layout on each tick, progressively getting closer to the desired size and location. Where it becomes fun is how you calculate the getting closer part. AnimatingPanelBase uses some physics (borrowed from Kevin and then massively tweaked) but you could build whatever you want for that.

HowToUseItToCreateanAnimatedPanel

It’s really simple. Here’s your checklist for converting your custom panel into an animating panel:

  1. Download the source.
  2. Add AnimatingPanelBase.cs and Vector.cs to your project.
  3. Change your panel’s base class from Panel to AnimatingPanelBase.
  4. Find the ArrangeOverride method and change child.Arrange(someRect) (or the equivalent) to base.SetElementLocation(child, someRect).

If you download the code, you’ll get the source for two simple animated panels: AnimatingCanvas and UniformWrapPanel. These were both created with a goal of simplicity rather than completeness (so buyer beware) but they should do a good job of demonstrating how to use AnimatingPanelBase. Here’s the entire source for AnimatingCanvas:

public class AnimatingCanvas : AnimatingPanelBase
{
    // The MeasureOverride method is your chance to ask
    // all of your children how big they want to be
 
    protected override Size MeasureOverride(Size availableSize)
    {
        Size YouCanBeAsBigAsYouWant = 
            new Size(double.PositiveInfinity, double.PositiveInfinity);
 
        foreach (UIElement element in this.Children)
        {
            element.Measure(YouCanBeAsBigAsYouWant);
        }
        return new Size();
    }
 
    // The ArrangeOverride method is your chance to place
    // and size all of your children
 
    protected override Size ArrangeOverride(Size finalSize)
    {
        double top = 0;
        double left = 0;
        double width = 0;
        double height = 0;
 
        foreach (UIElement element in this.Children)
        {
            top = (double) element.GetValue(Canvas.TopProperty);
            left = (double) element.GetValue(Canvas.LeftProperty);
            width = element.DesiredSize.Width;
            height = element.DesiredSize.Height;
 
            // This is the line of code that you would normally use to
            // arrange an element.  
            //element.Arrange(new Rect(left, top, width, height));
 
            // With AnimatingBasePanel, you call SetElementLocation instead
            base.SetElementLocation(element, 
                new Rect(left, top, width, height));
        }
 
        return finalSize;
    }
}

HowToCustomizetheAnimation

Once you’ve got your panel up and running, you’ve got some knobs that you can tweak to get the animation right:

IsAnimationEnabled This turns animation on and off. If you turn it off, it should behave like any other panel (and be roughly as efficient).

Force In Kevin’s code, this was called attraction. In the physics engine of AnimatingPanelBase, this is the amount of force that is drawing the item toward its new location.

Resistance This is the opposing force to Force. The more resistance there is, the less effect the Force has. Increasing Force and reducing Resistance will make the panel more “springy.” Increasing the Force and increasing Resistance will the panel fast but accurate.

Milliseconds The panel runs on a timer and this is the number of Milliseconds between each tick on the timer. It’s the inverse of Frame rate (in fact, we may want to re-expose this some day as FrameRate and then do the math to invert it).

Randomness When the actual location of the item gets calculated, a randomization component gets introduced to make the motion look more lifelike. The trade-off, of course, is that it’s a lot less precise.

SnapPrecision As an item approaches it’s desired location during the animation, it begins to slow down. Once the item gets close, we “snap” it into its final location. This is particularly useful when the physics is configured such that the item moves really slowly at the end of the animation. In that case, it can appear to “jiggle” into place at the end as it moves just fractions of a pixel on each update. The value for SnapPrecision is the distance at which the item snaps.

A good way to understand how these work is to tweak the values in the AnimatingCanvas demo (below).

KnownIssues

The biggest known issue right now is related to the Visibility property. If an item is collapsed while in motion, it’s rendered location appears to stop getting updates. So, when the item is made visible again it might appear to be in the wrong spot (the same spot where it was when it was collapsed).

This problem is definitely fixable and if you fix it, let me know. So far I just haven’t had a chance to track down a solution. The source of the problem, though, seems to be that when an item is collapsed, Silverlight stops updating it’s render location. When the item is made visible again, AnimatingBasePanel thinks it’s already been placed in the right location so it leaves it alone.

In the meantime, the Alphabet sample shows how you can introduce a new property (other than Visibility) to hide or show items. This is a hack, but its a straightforward one that works until we work out the Visibility issue.

WhereToUseIt

The truth is that I end up using this all over the place, maybe even abusing it. It’s just a panel though, so you can use it anywhere that you would use a panel (like as the ItemsPanel in a ListBox). In addition to the two demos, it’s also the way I handle the motion on the homepage of nerdplusart. So, you should feel free to use this too and please let me know if and where you do…especially if you push some boundaries or do something new with it.

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *