This post discusses a small set of classes we use to do dynamic animation in XAML apps – animation where the developer, at design time, might not know a lot about what needs to be animated and when. I’ve been using this “infrastructure” for a few months now and it seems to fill it’s niche pretty well…
First, a little background…
The various XAML infrastructures (WPF, Silverlight, Windows Store apps) have built in support for animation through Storyboards. Storyboards are non-visual elements that orchestrate an animation sequence involving one or more visual (and sometimes non visual) elements on the screen. The animation is executed primarily through the DependencyObject infrastructure that XAML brings to the table (which, incidentally, means animations do not need to be visual – they can just affect internal object states that are not usually considered animation).
For the purpose of this post, you don’t really need to understand storyboarding in XAML, but it would help you understand what’s happening under the covers.
Storyboard advantages and disadvantages
For pre-canned animation that does not vary and that needs to be carefully orchestrated, Storyboards shine. Especially when paired with good tools like Blend (once you figure out how it works), Storyboards are great. They let you create very pleasing effects, transitions and animations with a minimum amount of work. Furthermore, Storyboards that are expressed in XAML are declarative, and as such can easily be parsed “understood” and modified by external tools (like Blend).
Where Storyboard fall short, in my opinion, is when the developer has a set of elements they want to animate, but information such as the number of elements, their position, their size etc is not necessarily known in advance. Similarly – if the stages of the animation can change arbitrarily, Storyboards don’t really play well with that.
The reasons behind these issues all stem from the fact that you cannot modify a Storyboard while it’s “in flight” – once a Storyboard starts up, any changes (other than pausing and restarting) cannot be made. Furthermore, when a Storyboard stops, all the elements it animated “snap back” to their original position before the animation. Often, you will run a Storyboard indefinitely, essentially “pinning” the end-of-animation values it has for all the elements it affects. Another subtle issue is that even if you wrote extensions for Storyboards that will let you stop one in it’s tracks, modify it, and continue from that same spot (not trivial by any stretch of the imagination), the animations will seem to “jerk” as Easing functions applied to the animations will be recalculated from scratch, causing the animations to seem off.
Writing your own animation engine
The issues Storyboards have can be fixed by manually animating objects. Writing your own code, with loops and timing etc that will allow you to modify values of properties on UI elements, making them animate. There are two big issues with this:
1. It’s a lot of work – creating an animation engine that compensates for rendering lag, for difference between performance and for periods of heavy animation is a non-trivial task. Worse – it’s already been done by Microsoft – it’s called a Storyboard!
2. It’s not going to be as efficient – the XAML infrastructure can make a lot of assumptions (and has more internal knowledge) than you ever will on what’s going on inside it. What this means is that a ton of the code that actually does the animation will actually run on a thread different than the UI thread – a privilege we as 3rd party developers don’t have.
Goals for our solution
The solution provided here has 2 main goals:
1. Make use of the existing XAML animation infrastructure to animate UI elements.
2. Make it so that these animations can be easily orchestrated in code and have them be individually modifiable so that any animation can be changed “in flight”.
So.. What’s your solution?
The next 2-3 posts are going to show the solution I came up with to work around the limitations of doing truly dynamic animation. I will then show a (very) simple app that will make use of said animation infrastructure.
The dynamic (or “Managed”) animation system is fairly simple and is based on the following concepts:
- Granularity: Each managed animation consists of a single Storyboard and usually one or two timelines inside said Storyboard. That’s different from how you usually do animation in XAML which is by having a single Storyboard handling multiple time lines.
- Element-centric: Said storyboards are attached to a given FrameworkElement. If you want to move an image on your canvas from point A to point B, you will apply a single managed animation to it that will do that (a Storyboard, with 2 timelines, one animating Canvas.Top and one animating Canvas.Left). If you also want to animate the opacity of the element, you will also apply a second managed animation (orthogonally) which will handle that.
- Self managing: Animations are asynchronous in nature. The developer may decide to abruptly apply a different animation to the same element in essence interrupting the previous one. In these cases, the developer need not handle the cancellation (usually) – they just apply the new animation and the previous one will stop applying.
- Composition/orchestration through code: Orchastration of animation will happen through code and through the new facilities built into .NET 4.5 – if the developer wants to wait for two separate managed animations to complete, they can simply await both animations.
That’s it! The next post will discuss the basic building block – the ManagedAnimation class, how it works and what it does.