@@ -241,9 +241,8 @@ private static void IsPopupOpenPropertyChangedCallback(DependencyObject dependen
241
241
Mouse . Capture ( null ) ;
242
242
}
243
243
244
- if ( newValue )
245
- popupBox . AnimateChildren ( ) ;
246
244
245
+ popupBox . AnimateChildrenIn ( ! newValue ) ;
247
246
popupBox . _popup ? . RefreshPosition ( ) ;
248
247
249
248
VisualStateManager . GoToState ( popupBox , newValue ? PopupIsOpenStateName : PopupIsClosedStateName , true ) ;
@@ -299,6 +298,21 @@ public PopupBoxPopupMode PopupMode
299
298
set { SetValue ( PopupModeProperty , value ) ; }
300
299
}
301
300
301
+ /// <summary>
302
+ /// Get or sets how to unfurl controls when opening the popups. Only child elements of type <see cref="ButtonBase"/> are animated.
303
+ /// </summary>
304
+ public static readonly DependencyProperty UnfurlOrientationProperty = DependencyProperty . Register (
305
+ "UnfurlOrientation" , typeof ( Orientation ) , typeof ( PopupBox ) , new PropertyMetadata ( Orientation . Vertical ) ) ;
306
+
307
+ /// <summary>
308
+ /// Gets or sets how to unfurl controls when opening the popups. Only child elements of type <see cref="ButtonBase"/> are animated.
309
+ /// </summary>
310
+ public Orientation UnfurlOrientation
311
+ {
312
+ get { return ( Orientation ) GetValue ( UnfurlOrientationProperty ) ; }
313
+ set { SetValue ( UnfurlOrientationProperty , value ) ; }
314
+ }
315
+
302
316
/// <summary>
303
317
/// Framework use. Provides the method used to position the popup.
304
318
/// </summary>
@@ -444,56 +458,110 @@ private CustomPopupPlacement[] GetPopupPlacement(Size popupSize, Size targetSize
444
458
return new [ ] { new CustomPopupPlacement ( point , PopupPrimaryAxis . Horizontal ) } ;
445
459
}
446
460
447
- private void AnimateChildren ( )
461
+ private void AnimateChildrenIn ( bool reverse )
448
462
{
449
463
if ( _popupContentControl == null ) return ;
450
464
if ( VisualTreeHelper . GetChildrenCount ( _popupContentControl ) != 1 ) return ;
451
465
var contentPresenter = VisualTreeHelper . GetChild ( _popupContentControl , 0 ) as ContentPresenter ;
452
466
453
467
var controls = contentPresenter . VisualDepthFirstTraversal ( ) . OfType < ButtonBase > ( ) ;
454
- double translateYFrom ;
455
- if ( PlacementMode == PopupBoxPlacementMode . TopAndAlignCentres
456
- || PlacementMode == PopupBoxPlacementMode . TopAndAlignLeftEdges
457
- || PlacementMode == PopupBoxPlacementMode . TopAndAlignRightEdges
458
- || PlacementMode == PopupBoxPlacementMode . LeftAndAlignBottomEdges
459
- || PlacementMode == PopupBoxPlacementMode . RightAndAlignBottomEdges )
468
+ double translateCoordinateFrom ;
469
+ if ( ( PlacementMode == PopupBoxPlacementMode . TopAndAlignCentres
470
+ || PlacementMode == PopupBoxPlacementMode . TopAndAlignLeftEdges
471
+ || PlacementMode == PopupBoxPlacementMode . TopAndAlignRightEdges
472
+ || PlacementMode == PopupBoxPlacementMode . LeftAndAlignBottomEdges
473
+ || PlacementMode == PopupBoxPlacementMode . RightAndAlignBottomEdges
474
+ || ( UnfurlOrientation == Orientation . Horizontal &&
475
+ (
476
+ PlacementMode == PopupBoxPlacementMode . LeftAndAlignBottomEdges
477
+ || PlacementMode == PopupBoxPlacementMode . LeftAndAlignMiddles
478
+ || PlacementMode == PopupBoxPlacementMode . LeftAndAlignTopEdges
479
+ ) )
480
+ ) )
460
481
{
461
482
controls = controls . Reverse ( ) ;
462
- translateYFrom = 40 ;
483
+ translateCoordinateFrom = 80 ;
463
484
}
464
485
else
465
- translateYFrom = - 40 ;
486
+ translateCoordinateFrom = - 80 ;
487
+
488
+ var translateCoordinatePath =
489
+ "(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform."
490
+ + ( UnfurlOrientation == Orientation . Horizontal ? "X)" : "Y)" ) ;
491
+
492
+ var sineEase = new SineEase ( ) ;
466
493
467
494
var i = 0 ;
468
495
foreach ( var uiElement in controls )
469
- {
496
+ {
497
+ var deferredStart = i ++ * 20 ;
498
+ var deferredEnd = deferredStart + 200.0 ;
499
+
500
+ var absoluteZeroKeyTime = KeyTime . FromPercent ( 0.0 ) ;
501
+ var deferredStartKeyTime = KeyTime . FromTimeSpan ( TimeSpan . FromMilliseconds ( deferredStart ) ) ;
502
+ var deferredEndKeyTime = KeyTime . FromTimeSpan ( TimeSpan . FromMilliseconds ( deferredEnd ) ) ;
503
+
504
+ var elementTranslateCoordinateFrom = translateCoordinateFrom * i ;
505
+ var translateTransform = new TranslateTransform (
506
+ UnfurlOrientation == Orientation . Vertical ? 0 : elementTranslateCoordinateFrom ,
507
+ UnfurlOrientation == Orientation . Vertical ? elementTranslateCoordinateFrom : 0 ) ;
508
+
470
509
var transformGroup = new TransformGroup
471
- {
510
+ {
472
511
Children = new TransformCollection ( new Transform [ ]
473
512
{
474
- new ScaleTransform ( .5 , .5 ) ,
475
- new TranslateTransform ( 0 , translateYFrom )
513
+ new ScaleTransform ( 0 , 0 ) ,
514
+ translateTransform
476
515
} )
477
516
} ;
478
517
uiElement . SetCurrentValue ( RenderTransformOriginProperty , new Point ( .5 , .5 ) ) ;
479
518
uiElement . RenderTransform = transformGroup ;
480
519
481
- var scaleXAnimation = new DoubleAnimation ( .5 , 1 , new Duration ( TimeSpan . FromMilliseconds ( 100 ) ) ) ;
520
+ var opacityAnimation = new DoubleAnimationUsingKeyFrames ( ) ;
521
+ opacityAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , absoluteZeroKeyTime , sineEase ) ) ;
522
+ opacityAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , deferredStartKeyTime , sineEase ) ) ;
523
+ opacityAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 1 , deferredEndKeyTime , sineEase ) ) ;
524
+ Storyboard . SetTargetProperty ( opacityAnimation , new PropertyPath ( "Opacity" ) ) ;
525
+ Storyboard . SetTarget ( opacityAnimation , uiElement ) ;
526
+
527
+ var scaleXAnimation = new DoubleAnimationUsingKeyFrames ( ) ;
528
+ scaleXAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , absoluteZeroKeyTime , sineEase ) ) ;
529
+ scaleXAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , deferredStartKeyTime , sineEase ) ) ;
530
+ scaleXAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 1 , deferredEndKeyTime , sineEase ) ) ;
482
531
Storyboard . SetTargetProperty ( scaleXAnimation , new PropertyPath ( "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" ) ) ;
483
532
Storyboard . SetTarget ( scaleXAnimation , uiElement ) ;
484
- var scaleYAnimation = new DoubleAnimation ( .5 , 1 , new Duration ( TimeSpan . FromMilliseconds ( 100 ) ) ) ;
533
+
534
+ var scaleYAnimation = new DoubleAnimationUsingKeyFrames ( ) ;
535
+ scaleYAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , absoluteZeroKeyTime , sineEase ) ) ;
536
+ scaleYAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , deferredStartKeyTime , sineEase ) ) ;
537
+ scaleYAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 1 , deferredEndKeyTime , sineEase ) ) ;
485
538
Storyboard . SetTargetProperty ( scaleYAnimation , new PropertyPath ( "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" ) ) ;
486
539
Storyboard . SetTarget ( scaleYAnimation , uiElement ) ;
487
- var translateYAnimation = new DoubleAnimation ( translateYFrom , 0 , new Duration ( TimeSpan . FromMilliseconds ( 100 ) ) ) ;
488
- Storyboard . SetTargetProperty ( translateYAnimation , new PropertyPath ( "(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)" ) ) ;
489
- Storyboard . SetTarget ( translateYAnimation , uiElement ) ;
540
+
541
+ var translateCoordinateAnimation = new DoubleAnimationUsingKeyFrames ( ) ;
542
+ translateCoordinateAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( elementTranslateCoordinateFrom , absoluteZeroKeyTime , sineEase ) ) ;
543
+ translateCoordinateAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( elementTranslateCoordinateFrom , deferredStartKeyTime , sineEase ) ) ;
544
+ translateCoordinateAnimation . KeyFrames . Add ( new EasingDoubleKeyFrame ( 0 , deferredEndKeyTime , sineEase ) ) ;
545
+
546
+ Storyboard . SetTargetProperty ( translateCoordinateAnimation , new PropertyPath ( translateCoordinatePath ) ) ;
547
+ Storyboard . SetTarget ( translateCoordinateAnimation , uiElement ) ;
548
+
490
549
var storyboard = new Storyboard ( ) ;
550
+ storyboard . Children . Add ( opacityAnimation ) ;
491
551
storyboard . Children . Add ( scaleXAnimation ) ;
492
552
storyboard . Children . Add ( scaleYAnimation ) ;
493
- storyboard . Children . Add ( translateYAnimation ) ;
494
- storyboard . BeginTime = TimeSpan . FromMilliseconds ( i ++ * 20 ) ;
553
+ storyboard . Children . Add ( translateCoordinateAnimation ) ;
554
+
555
+ if ( reverse )
556
+ {
557
+ storyboard . AutoReverse = true ;
558
+ storyboard . Begin ( ) ;
559
+ storyboard . Seek ( TimeSpan . FromMilliseconds ( deferredEnd ) ) ;
560
+ storyboard . Resume ( ) ;
495
561
496
- storyboard . Begin ( ) ;
562
+ }
563
+ else
564
+ storyboard . Begin ( ) ;
497
565
}
498
566
}
499
567
0 commit comments