Two of my favorite animation classes in the Windows Presentation Foundation are PointAnimationUsingPath and MatrixAnimationUsingPath. Both these animations define a property of type PathGeometry that lets you animate a point along a complex series of connected lines, arcs, and Bezier curves. They even let you obtain a tangent to this line so you can rotate animated objects to be tangent or perpendicular to the path. I used MatrixAnimationUsingPath to
move a unicycle around a two-dimensional terrain, and I used PointAnimationUsingPath to make a
pie slice animation.

Well, that was a long time ago. In the past several years I haven't been coding for WPF as much as I've been coding for Silverlight, and then Silverlight for Windows Phone, and now the Windows Runtime of Windows 8 (which might deviously be called "Silverlight for Windows"). Silverlight and WinRT are missing a lot of the cooler stuff in WPF. Consequently, those of us whose minds have been expanded by the wealth of WPF goodies are sometimes forced to code klunky work-arounds.

I got an email this morning from someone asking if I could adapt that pie slice animation for Windows 8, and of course I had to drop everything I was doing to try to figure it out.

Drawing a pie slice in WPF, Silverlight, and the WinRT involves creating a PathGeometry that consists of two straight lines from the center of the pie to the circumference (the second of these lines can be drawn automatically to close the figure) and an ArcSegment. The ArcSegment draws an arc between two points based on a particular ellipse size, a SweepDirection (clockwise or counter-clockwise) and a Boolean IsLargeArc property. This ArcSegment is great if you just have two points and you want to connect them with an arc of a particular curvature. But it's not so great if you need to specify the center of the circle (or ellipse). In that case, the two points need to be on the circumference of a circle at that center, and they need to be calculated.

An animated pie slice requires moving a point along the circumference of a circle. It's easiest to animate a sweep angle from 0 to 360 degrees, and then calculate a point on the circumference from that. The calculation is trivial, but for coding purposes the real question is where should that calculation be performed.

But I knew that wasn't a good solution either, because the pie slice requires a second animation: The IsLargeArc property needs to be flipped from false to true when the sweep angle is greater than 180 degrees. You definitely want the two animations to be performed in synchronization or glitches will result.

Moreover, there are other good reasons to make use of WinRT's built-in animation, for example, to use easing functions if those are also desired.

So I began gravitating around the idea of creating a class that would be a target of a WinRT animation and perform the necessary calculations and provide this calculated value to the rest of the application. And I created this class called CircleGenerator:

This class derives from FrameworkElement so you can put it right in the visual tree of the XAML file. The Center and Radius properties can be set to fixed values, and Angle (being backed by a dependency property) can be the target of a XAML DoubleAnimation that goes from 0 to 360. Whenever the Angle property changes, the Point property is recalculated.

I could then define a binding on the Point property of ArcSegment to the Point property of CircleGenerator.

And that's when I discovered that WinRT restricts binding targets to properties of FrameworkElement derivatives.

At any rate, my CircleGenerator class got more complex. I realized that it would need TargetName and TargetProperty properties just like Storyboard so the CircleGenerator object itself could directly animate the Point property of the ArcSegment.

And it was around this time that I realized that animating IsLargeArc was also a problem because there's no such thing as a BooleanAnimationUsingKeyFrames in WinRT.

That led me to write a base class called ValuePusher that defines TargetName and TargetProperty properties, as well as a protected method named PushValue:

Notice that the target object and dependency property being targetted aren't actually determined until they're required by a call to PushValue. The problem is the FindName call used to obtain the named object in the XAML file. This will not be available until the page is completely loaded, which occurs after the TargetName property is set during XAML parsing.

And now the XAML is simple: The Storyboard defined as a resource contains two DoubleAnimation definitions, one for the sweep angle and another for the IsLargeArc property. The first animation targets the CircleGenerator and the second targets the BooleanGenerator, both of which are defined right in the visual tree by virtue of deriving from FrameworkElement:

The CircleGenerator and BooleanGenerator objects target the two properties of ArcSegment. The code-behind file merely starts the Storyboard going, and the roundabout result is a pie-slice animation for Windows 8:

It is stuff like this that kept me out of Silverlight. Everything takes a pile of odd hacks. WinRT just seems like more of the same WPF copy-cat-but-not-really game that I am just not keen on playing. But I guess it is still better than HTML5+JS.

I wish MS had never done Silverlight and focused that energy (and money) on making WPF awesome and use that as the basis for the Windows Metro stuff.

— Brad, Sun, 1 Apr 2012 23:03:15 -0400

Odd hacks???? This stuff is fun!!!! — Charles

Absolutely astounding. I was (honestly) *just* working on this very problem on my own when I decided to Google "animated pie piece" and look what I found. You solved a dozen problems I had not even reached yet. Thank you. Wow, and you just published this yesterday!