Update to the Picker Box control.

Last time I showed you how you could create the Picker Box functionality in your Windows Phone 7 applications. There're a few updates that I had to make in order to match Picker Box's behavior to it snative counterpart.

First of all you will probably notice that the native control will react on selecting an item even if it's already selected. The reason PickerBoxDialog didn't do it is because we are hooked up into the listbox_SelectedChanged event. To make our control to behave we can hook up into the MouseLefButtonUp event on each ListBoxItem in the ListBox control. This is done in the PrepareStoryboards method: To fix this I made the ListBox selection mode to be multi-select and added some logic to manipulate with RemovedItems and AddedItems.

The other issue with the code which I posted before is that the animations that are executed on the dialog's open or close not exactly match the native's dialog behavior. If you watch it closely (I even recorded the screen capture and tried to brake them into a separate frames) you will notice that the native animations have this "rolling" effect. As if the animations on each item are not executed at the same time, but there's a certain delay before animation on each item is started. Thanks to the help of internal folks I was able to figure out how to get this implemented. The "secret" ingredient to achieve the "rolling" effect is to set the BeginTime for each animation with an offset for each item. Also when watching the recording of the screen capture I've noticed that besides the rotational animation, there's also an animation that changes the opacity of the item going on. Here's the snippet that you will see inside of the PrepareStoryboards method:

 // Create open animation
animationOpen = CreateRotationAnimation(item, -120, 0, 200, beginTime);
animationOpacity = CreateOpacityAnimation(item, 0, 1, 200, beginTime);   
// Add it to the storyboard
OpenStoryboard.Children.Add(animationOpen);
OpenStoryboard.Children.Add(animationOpacity);
// Create close animation
animationClose = CreateRotationAnimation(item, 0, 90, 200, beginTime);
animationCloseOp = CreateOpacityAnimation(item, 1, 0, 200, beginTime);   
// Add it to the storyboard
CloseStoryboard.Children.Add(animationClose);
CloseStoryboard.Children.Add(animationCloseOp);
// Increment the begin time for animation
beginTime += 30;                     

You should also notice another change: I create animations in the code and add them to a children collection of the Storyboard. This means that I can start animation with a single call OpenStoryboard.Begin(). This is how the rotation animation is created:

  public static DoubleAnimation CreateRotationAnimation(DependencyObject obj, double from, double value, double milliseconds, double beginTime, EasingMode easing = EasingMode.EaseIn)
 {
       CubicEase ease = new CubicEase() { EasingMode = easing };
       DoubleAnimation animation = new DoubleAnimation();
 
       PropertyPath propPath = new PropertyPath("(UIElement.Projection).(PlaneProjection.RotationX)");
       animation.BeginTime = TimeSpan.FromMilliseconds(beginTime);
       animation.Duration = new Duration(TimeSpan.FromMilliseconds(milliseconds));
       animation.From = from;
       animation.To = Convert.ToDouble(value);
       animation.FillBehavior = FillBehavior.HoldEnd;
       //animation.EasingFunction = ease;
       Storyboard.SetTarget(animation, obj);           
       Storyboard.SetTargetProperty(animation, propPath);
 
       return animation;
 }

After all these changes I think the Pickup Box's behavior is pretty close to the native one. You can download the updated code here.

P.S. Seeing certain references to my code on the internet I have to make the following disclaimer:

DISCLAIMER: I don't work for the Windows Phone product group. The code that I create and share with you is not an official implementation of the functionality that exists on Windows Phone 7 device. I do it because I want to learn how to do it myself and I share it with you because I like helping developers to better adapt to a new platform and make the Windows Phone 7 the best device on the market.

UPDATE: I’ve made a few fixes and updates to the code:

  • Split the PrepareStoryboards method into two separate methods: PrepareOpenStoryboard and PrepareCloseStoryboard
  • Add code to recognize and create animations only for the visible items in the ListBox
  • Removed usage of the MouseLeftButtonUp event on the item. Instead I am using SelectionChanged event with a multi-select option on the ListBox