This blog post presents an attached behaviour that gracefully slides the contents of a list into view when used in conjunction with a Pivot control, emulating the Windows Phone 7 email application.
The Windows Phone 7 user interface is based on the Metro Design Language, which favours clear typography, content over chrome and simplicity. If you want to see practical applications of the Metro approach to design, I would highly recommend visiting Scott Barnes' blog over at riagenic.
Silverlight for Windows Phone 7 provides a basic Metro styling for elements such as Buttons and Checkboxes, it also has a few phone specific controls such as Pivot and Panorama. These controls make it easy to create a basic Metro interface, although again, I refer you to Scott Barnes' blog, Metro is not all about black and white! However, when using a WP7 phone you will probably notice that the native applications, email, maps and settings, have a bit more 'flair', lists gracefully slide into view, or 'peel' off the screen when an item is selected. Metro is not just about static style, it is "alive in motion".
The code in this blog post replicates the graceful slide effect seen in WP7 native applications when a moves from one list to another within a pivot as seen below. The code has been tested on real phone hardware to ensure that it performs well.
To use this code set the attached property
ListAnimation.IsPivotAnimated to true for the
ItemsControl) contained within a
PivotItem. Then apply the
ListAnimation.AnimationLevel to any element which you wish to animate as the list slides into view. The animation level describes the delay before each element is animated, for example, the markup below causes the summary to slide in just after the title, with the date following behind.
The code that achieves this effect is relatively straightforward, so I am going to present it all in one go (omitting all the usual attached property boiler-plate code):
IsPivotAnimated property is first attached, Linq-to-VisualTree is used to locate the parent
PivotControl in order to handle
SelectionChanged events. However, this is where things get tricky! If a
Pivot control contains just two
PivotItems, a change in selection is not enough to determine whether the pivot is scrolling to the left or the right! Therefore, we need to handle the
ManipulationCompleted event that is fired after the
SelectionChanged event to determine the direction of movement.
Once this is done, we can iterate over all of the items in the list, this assumes that the items are being hosted within a
VirtualizingStackPanel which is true for a
ListBox. For each item that is visible, another Linq query is used to find any that have the
AnimationLevel attached property set on them. For each element the animation is created an fired.
Dispatcher.BeginInvoke is used to start each group of animations in order to lessen the impact of starting 10-20 animations simultaneously. Without the use of the
Dispatcher, when testing on real hardware there was a small, but noticeable, judder in the sideways scrolling of the Pivot control at the point where the animations were fired. The use of
Dispatcher.BeginInvoke means that the construction and firing of the animations are now packaged as separate 'tasks' for each element in the list. This means that they do not have to be executed as a single unit of work, allowing the phone to fire a few animations, then perform other tasks. The net result is that the
Pivot control still scrolls smoothly between the
The code which creates the required animation is given below, it simply adds a
TranslateTransform to the element and creates the required animation / storyboard.
Interestingly I tried using the Artefact Animator, which has a nice concise API for creating animations in code-behind. However, because it animates elements by setting properties directly, it does not perform well on Windows Phone 7, which can execute storyboards on the composition thread in order to improve performance.
You can download the full sourcecode here: ListAnimation.zip