Thursday, January 31, 2008

WPF CoverFlow Clone

I recently decided to spend some time hacking up a CoverFlow clone in WPF. Of course, what I managed to achieve in the space of a day is nowhere near as good as the real CoverFlow application that Apple deploys but that's not the point! The point is, it amazes me how quickly and effortlessly I was able to do it with the power of WPF. It also amazes me how long something similar would have taken in any previous technology like Windows Forms or Win32!

Here's what the 'final' XBAP version looks like:




My approach was to almost completely restyle a ListBox. The first step was to redefine the ControlTemplate of ListBoxItem to be a Grid of 1 row and 1 column containing a StackPanel which in turn contained both the ContentPresenter and a Rectangle. The rectangle is there to produce the reflected image of the ContentPresenter.

Here's the XAML for doing that:





The VisualBrush used to paint the Rectangle has to be flipped in the Y-axis with a ScaleTransform and then put back into the correct position with the TranslateTransform. The TranslateTransform figures out how much to offset in the Y axis via databinding to the ActualHeight of the ContentPresenter. The OpacityMask applied to the Rectangle ensures that the reflection gradually dissolves away.




The StackPanel that contains the ContentPresenter and Rectangle (reflected image) looks like this:





This has a couple of transforms that do nothing until they are animated later; a TranslateTransform and a ScaleTransform.



When the ListBoxItem is selected, several animations run in parallel, effectively moving the StackPanel down in the Y axis by running the TranslateTransform while at the same time running a ScaleTransform which enlarges it in X and Y. The combined effect of these animations running in parallel is the sensation that the selected ListBoxItem springs forward towards the end user.



The animations are initiated by EventTrigger's; one each for the routed events: ListBoxItem.Selected and ListBoxItem.Unselected. Here's the XAML for the animations in their respective EventTrigger's





When the ListBoxItem becomes Unselected, the Unselected EventTrigger ensures the StackPanel moves back into it's original position and size prior to being selected - effectively reversing the work done of the Selected EventTrigger.