/// <summary>
        /// Fades the element out using the FadeOutThemeAnimation.
        /// </summary>
        /// <remarks>
        /// Opacity property of the element is not affected.<br/>
        /// The duration of the visible animation itself is not affected by the duration parameter. It merely indicates how long the Storyboard will run.<br/>
        /// If FadeOutThemeAnimation was already run before and FadeInThemeAnimation was not run after that - nothing will happen.<br/>
        /// </remarks>
        /// <param name="dob"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        public static async Task FadeOut(this DependencyObject dob, TimeSpan? duration = null)
        {
            var fadeOutStoryboard = new Storyboard();
            var fadeOutAnimation = new FadeOutThemeAnimation();

            if (duration != null)
            {
                fadeOutAnimation.Duration = duration.Value;
            }

            Storyboard.SetTarget(fadeOutAnimation, dob);
            fadeOutStoryboard.Children.Add(fadeOutAnimation);
            await fadeOutStoryboard.BeginAsync();
        }
        /// <summary>
        /// Fades the element in using the FadeInThemeAnimation.
        /// </summary>
        /// <remarks>
        /// Opacity property of the element is not affected.<br/>
        /// The duration of the visible animation itself is not affected by the duration parameter. It merely indicates how long the Storyboard will run.<br/>
        /// If FadeOutThemeAnimation was not used on the element before - nothing will happen.<br/>
        /// </remarks>
        /// <param name="dob"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        public static async Task FadeIn(this DependencyObject dob, TimeSpan? duration = null)
        {
            ((FrameworkElement)dob).Visibility = Visibility.Visible;
            var fadeInStoryboard = new Storyboard();
            var fadeInAnimation = new FadeInThemeAnimation();

            if (duration != null)
            {
                fadeInAnimation.Duration = duration.Value;
            }
            
            Storyboard.SetTarget(fadeInAnimation, dob);
            fadeInStoryboard.Children.Add(fadeInAnimation);
            await fadeInStoryboard.BeginAsync();
        }
        /// <summary>
        /// Animates the opacity of an element
        /// </summary>
        /// <param name="element">The element to animate</param>
        /// <param name="finalOpacity">Final Opacity</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> AnimateOpacityToAsync(this FrameworkElement element, double finalOpacity,
            double durationInSeconds, Action OnComplete = null)
        {
            ValidateForNull(element);
            ValidateCompositeTransform(element);
            if (element.RenderTransform == null) element.RenderTransform = new CompositeTransform();

            Storyboard sb = new Storyboard();
            DoubleAnimation opacityAnimation = CreateDoubleAnimation(element,
                durationInSeconds, finalOpacity,
                "(FrameworkElement.Opacity)");

            sb.Children.Add(opacityAnimation);
            await sb.BeginAsync();
            return sb;
        }
        /// <summary>
        /// Fades the element in using a custom DoubleAnimation of the Opacity property.
        /// </summary>
        /// <param name="dob"></param>
        /// <param name="duration"></param>
        /// <param name="easingFunction"> </param>
        /// <returns></returns>
        public static async Task FadeInCustom(this DependencyObject dob, TimeSpan? duration = null, EasingFunctionBase easingFunction = null)
        {
            var fadeInStoryboard = new Storyboard();
            var fadeInAnimation = new DoubleAnimation();

            if (duration == null)
                duration = TimeSpan.FromSeconds(0.4);

            fadeInAnimation.Duration = duration.Value;
            fadeInAnimation.To = 1.0;
            fadeInAnimation.EasingFunction = easingFunction;

            Storyboard.SetTarget(fadeInAnimation, dob);
            Storyboard.SetTargetProperty(fadeInAnimation, "Opacity");
            fadeInStoryboard.Children.Add(fadeInAnimation);
            await fadeInStoryboard.BeginAsync();
        }
 private async Task Animate()
 {
     var sb = new Storyboard();
     var daX = new DoubleAnimation();
     var daY = new DoubleAnimation();
     daX.Duration = TimeSpan.FromSeconds(0.8);
     daY.Duration = TimeSpan.FromSeconds(0.8);
     Storyboard.SetTarget(daX, AnimatedTransform);
     Storyboard.SetTarget(daY, AnimatedTransform);
     Storyboard.SetTargetProperty(daX, "X");
     Storyboard.SetTargetProperty(daY, "Y");
     daX.To = rand.Next(0, (int)AnimationPanel.ActualWidth - 100);
     daY.To = rand.Next(0, (int)AnimationPanel.ActualHeight - 100);
     sb.Children.Add(daX);
     sb.Children.Add(daY);
     await sb.BeginAsync();
 }
        private async Task AnimateToStraightenAsync()
        {
            if (_layoutGridTransform == null)
            {
                return;
            }

            var sb = new Storyboard();
            var dar = new DoubleAnimation();
            dar.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(dar, _layoutGridTransform);
            Storyboard.SetTargetProperty(dar, "Rotation");
            dar.To = 0;
            sb.Children.Add(dar);

            if (_titleTransform != null &&
                _titleGrid != null &&
                _titleTransform.Rotation == -180)
            {
                var dato = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(dato, _titleGrid);
                Storyboard.SetTargetProperty(dato, "Opacity");
                dato.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(0), Value = 1 });
                dato.KeyFrames.Add(new LinearDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = 0 });
                dato.KeyFrames.Add(new LinearDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.2), Value = 1 });
                sb.Children.Add(dato);

                var datr = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(datr, _titleTransform);
                Storyboard.SetTargetProperty(datr, "Rotation");
                datr.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = 0 });
                sb.Children.Add(datr);

                var datt = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(datt, _titleTransform);
                Storyboard.SetTargetProperty(datt, "TranslateY");
                datt.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = 0 });
                sb.Children.Add(datt);
            }

            await sb.BeginAsync();
            CleanupSnapProperties();
        }
        private async void OnBorderTapped(object sender, TappedRoutedEventArgs e)
        {
            if (_inAnimation)
            {
                return;
            }

            _inAnimation = true;
            _onBorderTappedCall++;
            var currentCall = _onBorderTappedCall;
            //var border = (Border)sender;
            //var grid = border.GetFirstAncestorOfType<UniformGrid>();

            //var sb = new Storyboard();

            //var beginTime = TimeSpan.Zero;

            //if (_isArrangedInGrid)
            //{
            //    var center = new Point(
            //        (grid.ActualWidth - border.ActualWidth) / 2,
            //        (grid.ActualHeight - border.ActualHeight) / 2);

            //    foreach (var child in grid.Children)
            //    {
            //        child.RenderTransform = new CompositeTransform();
            //        var nc = (NamedColor)((FrameworkElement)child).DataContext;
            //        var hsv = nc.Color.ToHsv();
            //        var targetX = center.X + center.X * Math.Sin(hsv.H * Math.PI / 180) * (0.25 + 0.75 * hsv.V);
            //        var targetY = center.Y - center.Y * Math.Cos(hsv.H * Math.PI / 180) * (0.25 + 0.75 * hsv.V);
            //        var actualPosition = child.TransformToVisual(grid).TransformPoint(new Point(0, 0));
            //        //Debug.WriteLine(actualPosition);
            //        var deltaX = targetX - actualPosition.X;
            //        var deltaY = targetY - actualPosition.Y;

            //        var xa = new DoubleAnimation();
            //        xa.BeginTime = beginTime;
            //        xa.Duration = TimeSpan.FromSeconds(1);
            //        xa.To = deltaX;
            //        Storyboard.SetTarget(xa, child.RenderTransform);
            //        Storyboard.SetTargetProperty(xa, "TranslateX");
            //        sb.Children.Add(xa);

            //        var ya = new DoubleAnimation();
            //        ya.BeginTime = beginTime;
            //        ya.Duration = TimeSpan.FromSeconds(1);
            //        ya.To = deltaY;
            //        Storyboard.SetTarget(ya, child.RenderTransform);
            //        Storyboard.SetTargetProperty(ya, "TranslateY");
            //        sb.Children.Add(ya);

            //        var aa = new DoubleAnimation();
            //        aa.BeginTime = beginTime;
            //        aa.Duration = TimeSpan.FromSeconds(1);
            //        aa.To = hsv.H;
            //        Storyboard.SetTarget(aa, child.RenderTransform);
            //        Storyboard.SetTargetProperty(aa, "Rotation");
            //        sb.Children.Add(aa);

            //        beginTime += TimeSpan.FromMilliseconds(5);
            //    }
            //}
            //else
            //{
            //    foreach (var child in grid.Children)
            //    {
            //        var nc = (NamedColor)((FrameworkElement)child).DataContext;

            //        var xa = new DoubleAnimation();
            //        xa.BeginTime = beginTime;
            //        xa.Duration = TimeSpan.FromSeconds(1);
            //        xa.To = 0;
            //        Storyboard.SetTarget(xa, child.RenderTransform);
            //        Storyboard.SetTargetProperty(xa, "TranslateX");
            //        sb.Children.Add(xa);

            //        var ya = new DoubleAnimation();
            //        ya.BeginTime = beginTime;
            //        ya.Duration = TimeSpan.FromSeconds(1);
            //        ya.To = 0;
            //        Storyboard.SetTarget(ya, child.RenderTransform);
            //        Storyboard.SetTargetProperty(ya, "TranslateY");
            //        sb.Children.Add(ya);

            //        var aa = new DoubleAnimation();
            //        aa.BeginTime = beginTime;
            //        aa.Duration = TimeSpan.FromSeconds(1);
            //        aa.To = 0;
            //        Storyboard.SetTarget(aa, child.RenderTransform);
            //        Storyboard.SetTargetProperty(aa, "Rotation");
            //        sb.Children.Add(aa);

            //        beginTime += TimeSpan.FromMilliseconds(5);
            //    }
            //}

            //sb.Begin();
            //_isArrangedInGrid = !_isArrangedInGrid;

            var border = (Border)sender;
            var grid = border.GetFirstAncestorOfType<UniformGrid>();

            if (_isArrangedInGrid)
            {
                var center = new Point(
                    (grid.ActualWidth - border.ActualWidth) / 2,
                    (grid.ActualHeight - border.ActualHeight) / 2);

                {
                    var sb1 = new Storyboard();

                    var beginTime = TimeSpan.Zero;

                    foreach (var child in grid.Children)
                    {
                        child.RenderTransform = new CompositeTransform();
                        child.RenderTransformOrigin = new Point(0.5, 0.5); 
                        var nc = (NamedColor)((FrameworkElement)child).DataContext;
                        var hsv = nc.Color.ToHsl();
                        var targetX = center.X +
                                        center.X * Math.Sin(hsv.H * Math.PI / 180) *
                                        (0.25 + 0.75 * Math.Min(hsv.L, hsv.S));
                        var targetY = center.Y -
                                        center.Y * Math.Cos(hsv.H * Math.PI / 180) *
                                        (0.25 + 0.75 * Math.Min(hsv.L, hsv.S));
                        var actualPosition =
                            child.TransformToVisual(grid)
                                    .TransformPoint(new Point(0, 0));
                        //Debug.WriteLine(actualPosition);
                        var deltaX = targetX - actualPosition.X;
                        var deltaY = targetY - actualPosition.Y;

                        var xa = new DoubleAnimation();
                        xa.BeginTime = beginTime;
                        xa.Duration = TimeSpan.FromSeconds(1);
                        xa.To = deltaX;
                        Storyboard.SetTarget(xa, child.RenderTransform);
                        Storyboard.SetTargetProperty(xa, "TranslateX");
                        sb1.Children.Add(xa);

                        var ya = new DoubleAnimation();
                        ya.BeginTime = beginTime;
                        ya.Duration = TimeSpan.FromSeconds(1);
                        ya.To = deltaY;
                        Storyboard.SetTarget(ya, child.RenderTransform);
                        Storyboard.SetTargetProperty(ya, "TranslateY");
                        sb1.Children.Add(ya);

                        var aa = new DoubleAnimation();
                        aa.BeginTime = beginTime;
                        aa.Duration = TimeSpan.FromSeconds(1);
                        aa.To = hsv.H;
                        Storyboard.SetTarget(aa, child.RenderTransform);
                        Storyboard.SetTargetProperty(aa, "Rotation");
                        sb1.Children.Add(aa);
                    }

                    await sb1.BeginAsync();
                }

                if (currentCall != _onBorderTappedCall)
                {
                    return;
                }

                const double revolutionDurationInS = 30d;

                foreach (var child in grid.Children)
                {
                    child.RenderTransform = new CompositeTransform();
                    child.RenderTransformOrigin = new Point(0.5, 0.5); 
                    var nc = (NamedColor)((FrameworkElement)child).DataContext;
                    var hsv = nc.Color.ToHsl();
                    var actualPosition = child.TransformToVisual(grid).TransformPoint(new Point(0, 0));

                    var sb = new Storyboard();
                    sb.RepeatBehavior = RepeatBehavior.Forever;

                    var minX = center.X - center.X * (0.25 + 0.75 * Math.Min(hsv.L, hsv.S)) - actualPosition.X;
                    var midX = center.X - actualPosition.X;
                    var maxX = center.X + center.X * (0.25 + 0.75 * Math.Min(hsv.L, hsv.S)) - actualPosition.X;
                    var minY = center.Y - center.Y * (0.25 + 0.75 * Math.Min(hsv.L, hsv.S)) - actualPosition.Y;
                    var midY = center.Y - actualPosition.Y;
                    var maxY = center.Y + center.Y * (0.25 + 0.75 * Math.Min(hsv.L, hsv.S)) - actualPosition.Y;

                    var xa = new DoubleAnimationUsingKeyFrames();
                    xa.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.Zero, Value = midX});
                    xa.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.25), Value = maxX, EasingFunction = new SineEase { EasingMode = EasingMode.EaseOut } });
                    xa.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.50), Value = midX, EasingFunction = new SineEase { EasingMode = EasingMode.EaseIn } });
                    xa.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.75), Value = minX, EasingFunction = new SineEase { EasingMode = EasingMode.EaseOut } });
                    xa.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 1.00), Value = midX, EasingFunction = new SineEase { EasingMode = EasingMode.EaseIn } });
                    Storyboard.SetTarget(xa, child.RenderTransform);
                    Storyboard.SetTargetProperty(xa, "TranslateX");
                    sb.Children.Add(xa);

                    var ya = new DoubleAnimationUsingKeyFrames();
                    ya.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.Zero, Value = minY });
                    ya.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.25), Value = midY, EasingFunction = new SineEase { EasingMode = EasingMode.EaseIn } });
                    ya.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.50), Value = maxY, EasingFunction = new SineEase { EasingMode = EasingMode.EaseOut } });
                    ya.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 0.75), Value = midY, EasingFunction = new SineEase { EasingMode = EasingMode.EaseIn } });
                    ya.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(revolutionDurationInS * 1.00), Value = minY, EasingFunction = new SineEase { EasingMode = EasingMode.EaseOut } });
                    Storyboard.SetTarget(ya, child.RenderTransform);
                    Storyboard.SetTargetProperty(ya, "TranslateY");
                    sb.Children.Add(ya);

                    var aa = new DoubleAnimation();
                    aa.Duration = TimeSpan.FromSeconds(revolutionDurationInS);
                    aa.From = 0;
                    aa.To = 360;
                    Storyboard.SetTarget(aa, child.RenderTransform);
                    Storyboard.SetTargetProperty(aa, "Rotation");
                    sb.Children.Add(aa);
                    //sb.BeginTime =
                    //    TimeSpan.FromSeconds(hsv.H * revolutionDurationInS / 360d);
                    sb.Begin();
                    sb.Seek(TimeSpan.FromSeconds(((hsv.H + 360) % 360) * revolutionDurationInS / 360d));
                }
            }
            else
            {
                var sb = new Storyboard();
                var beginTime = TimeSpan.Zero;

                foreach (var child in grid.Children)
                {
                    //var nc = (NamedColor)((FrameworkElement)child).DataContext;

                    var xa = new DoubleAnimation();
                    xa.BeginTime = beginTime;
                    xa.Duration = TimeSpan.FromSeconds(1);
                    xa.To = 0;
                    Storyboard.SetTarget(xa, child.RenderTransform);
                    Storyboard.SetTargetProperty(xa, "TranslateX");
                    sb.Children.Add(xa);

                    var ya = new DoubleAnimation();
                    ya.BeginTime = beginTime;
                    ya.Duration = TimeSpan.FromSeconds(1);
                    ya.To = 0;
                    Storyboard.SetTarget(ya, child.RenderTransform);
                    Storyboard.SetTargetProperty(ya, "TranslateY");
                    sb.Children.Add(ya);

                    var aa = new DoubleAnimation();
                    aa.BeginTime = beginTime;
                    aa.Duration = TimeSpan.FromSeconds(1);
                    aa.To = 0;
                    Storyboard.SetTarget(aa, child.RenderTransform);
                    Storyboard.SetTargetProperty(aa, "Rotation");
                    sb.Children.Add(aa);

                    //beginTime += TimeSpan.FromMilliseconds(5);
                }

                await sb.BeginAsync();
            }

            _isArrangedInGrid = !_isArrangedInGrid;
            _inAnimation = false;
        }
 internal async Task ScrollToVerticalOffsetWithAnimation(
     double offset,
     TimeSpan duration,
     EasingFunctionBase easingFunction)
 {
     var sb = new Storyboard();
     var da = new DoubleAnimation();
     da.EnableDependentAnimation = true;
     da.From = _scrollViewer.VerticalOffset;
     da.To = offset;
     da.EasingFunction = easingFunction;
     da.Duration = duration;
     sb.Children.Add(da);
     Storyboard.SetTarget(sb, _sliderVertical);
     Storyboard.SetTargetProperty(da, "Value");
     await sb.BeginAsync();
 }
 internal async Task ZoomToFactorWithAnimationAsync(
     double factor,
     TimeSpan duration,
     EasingFunctionBase easingFunction)
 {
     var sb = new Storyboard();
     var da = new DoubleAnimation
     {
         EnableDependentAnimation = true,
         From = this._scrollViewer.ZoomFactor,
         To = factor,
         EasingFunction = easingFunction,
         Duration = duration
     };
     sb.Children.Add(da);
     Storyboard.SetTarget(sb, this._sliderZoom);
     Storyboard.SetTargetProperty(da, "Value");
     await sb.BeginAsync();
 }
 internal async Task ScrollToHorizontalOffsetWithAnimationAsync(
     double offset,
     TimeSpan duration,
     EasingFunctionBase easingFunction)
 {
     var sb = new Storyboard();
     var da = new DoubleAnimation
     {
         EnableDependentAnimation = true,
         From = this._scrollViewer.HorizontalOffset,
         To = offset,
         EasingFunction = easingFunction,
         Duration = duration
     };
     sb.Children.Add(da);
     Storyboard.SetTarget(sb, this._sliderHorizontal);
     Storyboard.SetTargetProperty(da, "Value");
     await sb.BeginAsync();
 }
        /// <summary>
        /// Fades the element out using the FadeOutThemeAnimation.
        /// </summary>
        /// <remarks>
        /// Opacity property of the element is not affected.<br/>
        /// The duration of the visible animation itself is not affected by the duration parameter. It merely indicates how long the Storyboard will run.<br/>
        /// If FadeOutThemeAnimation was already run before and FadeInThemeAnimation was not run after that - nothing will happen.<br/>
        /// </remarks>
        /// <param name="element"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        public static async Task FadeOutAsync(this UIElement element, TimeSpan? duration = null)
        {
            var fadeOutStoryboard = new Storyboard();
            var fadeOutAnimation = new FadeOutThemeAnimation();

            if (duration != null)
            {
                fadeOutAnimation.Duration = duration.Value;
            }

            Storyboard.SetTarget(fadeOutAnimation, element);
            fadeOutStoryboard.Children.Add(fadeOutAnimation);
            await fadeOutStoryboard.BeginAsync();
        } 
        /// <summary>
        /// Rotates an element by relative angles
        /// </summary>
        /// <param name="element">Element to rotate</param>
        /// <param name="deltaAngles">Relative angles rotation</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> RotateByAsync(this FrameworkElement element, double deltaAngles,
         double durationInSeconds, Action OnComplete = null)
        {

            ValidateForNull(element);
            ValidateCompositeTransform(element);

            Storyboard sb = new Storyboard();

            DoubleAnimation rotationAnimation = CreateDoubleAnimation(element,
                durationInSeconds, deltaAngles + (element.RenderTransform as CompositeTransform).Rotation,
                "(FrameworkElement.RenderTransform).(CompositeTransform.Rotation)");


            sb.Children.Add(rotationAnimation);
            await sb.BeginAsync();
            if (OnComplete != null) OnComplete();
            return sb;
        }
        /// <summary>
        /// Begins the cascading transition asynchronously (waits for it to complete).
        /// </summary>
        /// <returns></returns>
        public async Task BeginCascadingTransitionAsync()
        {
            var transparentBrush =
                new SolidColorBrush(Colors.Transparent);
            LayoutRoot.Children.Clear();

            var totalDelay = TimeSpan.FromSeconds(0);

            var cascadeStoryboard = new Storyboard();

            var previousCharacterRect = new Rect(-100000,0,0,0);

            for (int i = 0; i < Text.Length; )
            {
                int j = 1;

                while (
                    i + j < Text.Length &&
                    Text[i + j] == ' ')
                {
                    j++;
                }

                var tt = new TranslateTransform();

                if (CascadeIn)
                {
                    tt.Y = FromVerticalOffset;
                }

                TextBlock tb = CreateTextBlock(tt);

                if (i > 0)
                {
                    tb.Inlines.Add(
                        new Run
                        {
                            Text = Text.Substring(0, i),
                            Foreground = transparentBrush
                        });
                }
                
                var singleLetterRun = new Run { Text = Text.Substring(i, j) };
                tb.Inlines.Add(singleLetterRun);
                //.GetPositionAtOffset(1, LogicalDirection.Backward)

                if (i + j < Text.Length)
                {
                    tb.Inlines.Add(
                        new Run
                        {
                            Text = Text.Substring(i + j),
                            Foreground = transparentBrush
                        });
                }

                LayoutRoot.Children.Add(tb);

                DoubleAnimationUsingKeyFrames opacityAnimation = null;

                if (UseFade)
                {
                    opacityAnimation = new DoubleAnimationUsingKeyFrames();

                    if (CascadeIn)
                        tb.Opacity = 0;

                    Storyboard.SetTarget(opacityAnimation, tb);
                    Storyboard.SetTargetProperty(opacityAnimation, "UIElement.Opacity");
                    cascadeStoryboard.Children.Add(opacityAnimation);
                }

                DoubleAnimationUsingKeyFrames yAnimation = null;

                if (CascadeIn || CascadeOut)
                {
                    yAnimation = new DoubleAnimationUsingKeyFrames();
                    Storyboard.SetTarget(yAnimation, tt);
                    Storyboard.SetTargetProperty(yAnimation, "TranslateTransform.Y");
                    cascadeStoryboard.Children.Add(yAnimation);
                }

                DoubleAnimationUsingKeyFrames rotationAnimation = null;
                PlaneProjection planeProjection = null;

                if (UseRotation)
                {
                    await tb.WaitForNonZeroSizeAsync();
                    //await Task.Delay(100);

                    var aw = tb.ActualWidth;
                    var ah = tb.ActualHeight;

                    var characterRect = tb.GetCharacterRect(i);
                    tb.Projection = planeProjection = new PlaneProjection();
                    planeProjection.CenterOfRotationX = (characterRect.X + (characterRect.Width / 2)) / aw;
                    
                    if (CascadeIn)
                        planeProjection.RotationY = FromRotation;

                    //var pointer = tb.ContentStart.GetPositionAtOffset(offset, LogicalDirection.Forward);
                    //var rect = pointer.GetCharacterRect(LogicalDirection.Forward);

                    //while (
                    //    rect == previousCharacterRect ||
                    //    rect.X - previousCharacterRect.X < 4)
                    //{
                    //    offset++;
                    //    if (offset > tb.ContentEnd.Offset)
                    //        break;
                    //    pointer = tb.ContentStart.GetPositionAtOffset(offset, LogicalDirection.Forward);
                    //    rect = pointer.GetCharacterRect(LogicalDirection.Forward);
                    //}

                    //previousCharacterRect = rect;

                    //var x = rect.X;
                    //var y = rect.Y;
                    //var w = rect.Width;
                    //var h = rect.Height;

                    //tb.Projection = planeProjection = new PlaneProjection();
                    //planeProjection.CenterOfRotationX = (x + (w / 2)) / aw;
                    //planeProjection.RotationY = FromRotation;

                    //if (!headerPrinted)
                    //{
                    //    Debug.WriteLine("ActualWidth: {0}", aw);
                    //    Debug.WriteLine("ActualHeight: {0}\r\n", ah);
                    //    Debug.WriteLine("po\ti\tj\tx\ty\tw\th\tpx");
                    //    headerPrinted = true;
                    //}

                    //Debug.WriteLine(
                    //    "{0:F0}\t{1:F0}\t{2:F0}\t{3:F0}\t{4:F0}\t{5:F0}\t{6:F0}\t{7:F3}",
                    //    pointer.Offset, i, j, x, y, w, h, planeProjection.CenterOfRotationX);

                    rotationAnimation = new DoubleAnimationUsingKeyFrames();
                    Storyboard.SetTarget(rotationAnimation, planeProjection);
                    Storyboard.SetTargetProperty(rotationAnimation, "PlaneProjection.RotationY");
                    cascadeStoryboard.Children.Add(rotationAnimation);

                    if (CascadeIn)
                    {
                        rotationAnimation.KeyFrames.Add(
                            new DiscreteDoubleKeyFrame
                            {
                                KeyTime = totalDelay,
                                Value = FromRotation
                            });
                        rotationAnimation.KeyFrames.Add(
                            new EasingDoubleKeyFrame
                            {
                                KeyTime = totalDelay + CascadeInDuration,
                                EasingFunction = CascadeInEasingFunction,
                                Value = 0
                            });
                    }

                    if (CascadeOut)
                    {
                        rotationAnimation.KeyFrames.Add(
                            new DiscreteDoubleKeyFrame
                            {
                                KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration,
                                Value = 0
                            });
                        rotationAnimation.KeyFrames.Add(
                            new EasingDoubleKeyFrame
                            {
                                KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration + CascadeOutDuration,
                                EasingFunction = CascadeOutEasingFunction,
                                Value = ToRotation
                            });
                    }
                }

                if (CascadeIn)
                {
                    yAnimation.KeyFrames.Add(
                        new DiscreteDoubleKeyFrame
                        {
                            KeyTime = totalDelay,
                            Value = FromVerticalOffset
                        });
                    yAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame
                        {
                            KeyTime = totalDelay + CascadeInDuration,
                            EasingFunction = CascadeInEasingFunction,
                            Value = 0
                        });

                    if (UseFade)
                    {
                        opacityAnimation.KeyFrames.Add(
                            new DiscreteDoubleKeyFrame
                            {
                                KeyTime = totalDelay,
                                Value = 0
                            });
                        opacityAnimation.KeyFrames.Add(
                            new EasingDoubleKeyFrame
                            {
                                KeyTime = totalDelay + CascadeInDuration,
                                EasingFunction = FadeInEasingFunction,
                                Value = 1.0
                            });
                    }
                }

                if (CascadeOut)
                {
                    yAnimation.KeyFrames.Add(
                        new DiscreteDoubleKeyFrame
                        {
                            KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration,
                            Value = 0
                        });
                    yAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame
                        {
                            KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration + CascadeOutDuration,
                            EasingFunction = CascadeOutEasingFunction,
                            Value = ToVerticalOffset
                        });

                    if (UseFade)
                    {
                        opacityAnimation.KeyFrames.Add(
                            new DiscreteDoubleKeyFrame
                            {
                                KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration,
                                Value = 1.00
                            });
                        opacityAnimation.KeyFrames.Add(
                            new EasingDoubleKeyFrame
                            {
                                KeyTime = totalDelay + (CascadeIn ? CascadeInDuration : TimeSpan.Zero) + HoldDuration + CascadeOutDuration,
                                EasingFunction = FadeOutEasingFunction,
                                Value = 0.0
                            });
                    }
                }

                totalDelay += CascadeInterval;
                i += j;
            }

            EventHandler<object> eh = null;
            eh = (s, e) =>
            {
                cascadeStoryboard.Completed -= eh;
                //LayoutRoot.Children.Clear();
                //var tb2 = CreateTextBlock(null);
                //tb2.Text = Text;
                //LayoutRoot.Children.Add(tb2);

#if CascadingTextBlock_REPEATFOREVER
                BeginCascadingTransition();
#else
                if (CascadeCompleted != null)
                    CascadeCompleted(this, EventArgs.Empty);
#endif
            };

            cascadeStoryboard.Completed += eh;
            await Task.Delay(StartDelay);
            await cascadeStoryboard.BeginAsync();
        }
        /// <summary>
        /// Starts the countdown and completes when the countdown completes.
        /// </summary>
        /// <param name="seconds">The seconds.</param>
        /// <returns></returns>
        public async Task StartCountdownAsync(int seconds)
        {
            _countingDown = true;

            this.Seconds = seconds;

            bool grow = true;

            while (this.Seconds > 0)
            {
                var sb = new Storyboard();

                if (grow)
                {
                    ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "grow");

                    var da = new DoubleAnimation
                    {
                        From = 0d,
                        To = 359.999d,
                        Duration = new Duration(TimeSpan.FromSeconds(1d)),
                        EnableDependentAnimation = true
                    };

                    sb.Children.Add(da);
                    sb.RepeatBehavior = new RepeatBehavior(1);

                    // Workaround for a problem animating custom dependency properties
                    //PART_RingSlice.SetBinding(
                    //   RingSlice.EndAngleProperty,
                    //   new Binding { Source = r1, Path = new PropertyPath("Opacity"), Mode = BindingMode.OneWay });
                    //Storyboard.SetTargetProperty(da, "Opacity");
                    //Storyboard.SetTarget(sb, r1);
                    Storyboard.SetTargetProperty(da, "EndAngle");
                    Storyboard.SetTarget(sb, PART_RingSlice);
                }
                else
                {
                    ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "shrink");

                    var da = new DoubleAnimation
                    {
                        From = 0d,
                        To = 359.999d,
                        Duration = new Duration(TimeSpan.FromSeconds(1d)),
                        EnableDependentAnimation = true
                    };

                    sb.Children.Add(da);
                    sb.RepeatBehavior = new RepeatBehavior(1);

                    //PART_RingSlice.SetBinding(
                    //   RingSlice.StartAngleProperty,
                    //   new Binding { Source = r2, Path = new PropertyPath("Opacity"), Mode = BindingMode.OneWay });
                    //Storyboard.SetTargetProperty(da, "Opacity");
                    //Storyboard.SetTarget(sb, r2);
                    Storyboard.SetTargetProperty(da, "StartAngle");
                    Storyboard.SetTarget(sb, PART_RingSlice);
                }

                PART_Label.Text = this.Seconds.ToString();
                
                ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "before animation");
                await sb.BeginAsync();
                ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "after animation");

                if (grow)
                {
                    PART_RingSlice.StartAngle = 0d;
                    PART_RingSlice.EndAngle = 359.999d;
                }
                else
                {
                    PART_RingSlice.StartAngle = 0d;
                    PART_RingSlice.EndAngle = 0d;
                }

                grow = !grow;
                this.Seconds--;
            }

            PART_Label.Text = this.Seconds.ToString();

            if (this.CountdownComplete != null)
            {
                ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "before countdowncomplete");
                CountdownComplete(this, new RoutedEventArgs());
                ////Debug.WriteLine(DateTime.Now.ToString("mm:ss.ffff") + "after countdowncomplete");
            }

            _countingDown = false;
        }
 /// <summary>
 /// Simulates a thread sleep
 /// </summary>
 /// <param name="durationInSeconds">Duration in seconds</param>
 /// <returns>Storyboard created</returns>
 public async static Task<Storyboard> BeginSleepStoryboardAsync(double durationInSeconds)
 {
     Storyboard sb = new Storyboard();
     sb.Duration = TimeSpan.FromSeconds(durationInSeconds);
     await sb.BeginAsync();
     return sb;
 }
        /// <summary>
        /// Animates a panel's background
        /// </summary>
        /// <param name="panel">The panel to have its color animated</param>
        /// <param name="color">Final color</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> AnimateSolidColorBackgroundToAsync(this Panel panel, Color color,
          double durationInSeconds, Action OnComplete = null)
        {
            ValidateForNull(panel);
            Storyboard sb = new Storyboard();

            ColorAnimation colorAnimation = CreateColorAnimation(panel,
                durationInSeconds, color,
                "(Panel.Background).(SolidColorBrush.Color)");


            sb.Children.Add(colorAnimation);
            await sb.BeginAsync();
            if (OnComplete != null) OnComplete();
            return sb;
        }
        /// <summary>
        /// Animates a shape to specific color
        /// </summary>
        /// <param name="shape">Shape to have color changed</param>
        /// <param name="color">Final color</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> AnimateSolidColorFillToAsync(this Shape shape, Color color,
            double durationInSeconds, Action OnComplete = null)
        {
            ValidateForNull(shape);
            Storyboard sb = new Storyboard();

            ColorAnimation colorAnimation = CreateColorAnimation(shape,
                durationInSeconds, color,
                "(Shape.Fill).(SolidColorBrush.Color)");


            sb.Children.Add(colorAnimation);
            await sb.BeginAsync();
            if (OnComplete != null) OnComplete();
            return sb;
        }
        /// <summary>
        /// Skews an element by relative values
        /// </summary>
        /// <param name="element">Element to skew</param>
        /// <param name="skewDeltaX">Final X skew</param>
        /// <param name="skewDeltaY">Final Y skew</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> SkewByAsync(this FrameworkElement element, double skewDeltaX, double skewDeltaY,
      double durationInSeconds, Action OnComplete = null)
        {

            ValidateForNull(element);
            ValidateCompositeTransform(element);

            Storyboard sb = new Storyboard();

            DoubleAnimation skewXAnimation = CreateDoubleAnimation(element,
                durationInSeconds, skewDeltaX + (element.RenderTransform as CompositeTransform).SkewX,
                "(FrameworkElement.RenderTransform).(CompositeTransform.SkewX)");

            DoubleAnimation skewYAnimation = CreateDoubleAnimation(element,
                durationInSeconds, skewDeltaY + (element.RenderTransform as CompositeTransform).SkewY,
                "(FrameworkElement.RenderTransform).(CompositeTransform.SkewY)");


            sb.Children.Add(skewXAnimation);
            sb.Children.Add(skewYAnimation);
            await sb.BeginAsync();
            if (OnComplete != null) OnComplete();
            return sb;
        }
        private async Task AnimateRotatedSnapAsync(double x, double y, double angle)
        {
            if (_layoutGridTransform == null)
            {
                return;
            }

            var sb = new Storyboard();

            var dax = new DoubleAnimation();
            dax.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(dax, _layoutGridTransform);
            Storyboard.SetTargetProperty(dax, "TranslateX");
            dax.To = x;
            sb.Children.Add(dax);

            var day = new DoubleAnimation();
            day.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(day, _layoutGridTransform);
            Storyboard.SetTargetProperty(day, "TranslateY");
            day.To = y;
            sb.Children.Add(day);

            var dar = new DoubleAnimation();
            dar.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(dar, _layoutGridTransform);
            Storyboard.SetTargetProperty(dar, "Rotation");
            dar.To = angle;
            sb.Children.Add(dar);

            if (_titleTransform != null &&
                _titleGrid != null &&
                angle == 180)
            {
                var dato = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(dato, _titleGrid);
                Storyboard.SetTargetProperty(dato, "Opacity");
                dato.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(0), Value = 1 });
                dato.KeyFrames.Add(new LinearDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = 0 });
                dato.KeyFrames.Add(new LinearDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.2), Value = 1 });
                sb.Children.Add(dato);

                var datr = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(datr, _titleTransform);
                Storyboard.SetTargetProperty(datr, "Rotation");
                datr.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = -180 });
                sb.Children.Add(datr);

                var datt = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(datt, _titleTransform);
                Storyboard.SetTargetProperty(datt, "TranslateY");
                datt.KeyFrames.Add(new DiscreteDoubleKeyFrame { KeyTime = TimeSpan.FromSeconds(.1), Value = -BorderThickness.Top });
                sb.Children.Add(datt);
            }

            this._currentSnapStoryboard = sb;
            await sb.BeginAsync();

            this._currentSnapStoryboard = null;

            if (_layoutGridTransform != null)
            {
                this.X = Math.Round(_layoutGridTransform.TranslateX);
                this.Y = Math.Round(_layoutGridTransform.TranslateY);
            }
        }
        private async Task AnimateStraightSnapAsync(double x, double y)
        {
            if (_layoutGridTransform == null)
            {
                return;
            }

            var sb = new Storyboard();

            var dax = new DoubleAnimation();
            dax.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(dax, _layoutGridTransform);
            Storyboard.SetTargetProperty(dax, "TranslateX");
            dax.To = x;
            sb.Children.Add(dax);

            var day = new DoubleAnimation();
            day.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(day, _layoutGridTransform);
            Storyboard.SetTargetProperty(day, "TranslateY");
            day.To = y;
            sb.Children.Add(day);

            var dar = new DoubleAnimation();
            dar.Duration = TimeSpan.FromSeconds(.2);
            Storyboard.SetTarget(dar, _layoutGridTransform);
            Storyboard.SetTargetProperty(dar, "Rotation");
            dar.To = 0;
            sb.Children.Add(dar);

            this._currentSnapStoryboard = sb;
            await sb.BeginAsync();

            this._currentSnapStoryboard = null;

            if (_layoutGridTransform != null)
            {
                this.X = Math.Round(_layoutGridTransform.TranslateX);
                this.Y = Math.Round(_layoutGridTransform.TranslateY);
            }
        }
        public async Task TransitionBackward(DependencyObject previousPage, DependencyObject newPage)
        {
            if (previousPage == null && newPage == null)
            {
                throw new InvalidOperationException();
            }

            if (previousPage == null)
            {
                await BackwardInAnimation.Animate(newPage);
            }
            else if (newPage == null)
            {
                await BackwardOutAnimation.Animate(previousPage);
            }
            else if (this.Mode == PageTransitionMode.Parallel)
            {
                var sb = new Storyboard();
                var outSb = BackwardOutAnimation.GetAnimation(previousPage);
                var inSb = BackwardInAnimation.GetAnimation(newPage);
                sb.Children.Add(outSb);
                sb.Children.Add(inSb);
                await sb.BeginAsync();
                sb.Stop();
                sb.Children.Clear();
                //await Task.WhenAll(
                //    BackwardOutAnimation.Animate(previousPage),
                //    BackwardInAnimation.Animate(newPage));
            }
            else
            {
                await BackwardOutAnimation.Animate(previousPage);
                await BackwardInAnimation.Animate(newPage);
            }
        }
        private async void SlideIn(ImageLoadedTransitionTypes transitionType)
        {
            _image.Opacity = _targetOpacity;

            // Built-in animations are nice, but not very customizable. Leaving this for posterity.
            ////var animation = new RepositionThemeAnimation
            ////{
            ////    FromVerticalOffset = _image.ActualHeight,
            ////    Duration = TimeSpan.FromSeconds(2)
            ////};

            ////Storyboard.SetTarget(animation, _image);

            var oldTransform = _image.RenderTransform;
            var tempTransform = new TranslateTransform();
            _image.RenderTransform = tempTransform;
            DoubleAnimation animation = null;

            switch (transitionType)
            {
                case ImageLoadedTransitionTypes.SlideUp:
                    animation = new DoubleAnimation
                    {
                        From = _image.ActualHeight,
                        To = 0,
                        Duration = TimeSpan.FromSeconds(1),
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
                    };

                    Storyboard.SetTargetProperty(animation, "Y");
                    break;
                case ImageLoadedTransitionTypes.SlideDown:
                    animation = new DoubleAnimation
                    {
                        From = -_image.ActualHeight,
                        To = 0,
                        Duration = TimeSpan.FromSeconds(1),
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
                    };

                    Storyboard.SetTargetProperty(animation, "Y");
                    break;
                case ImageLoadedTransitionTypes.SlideRight:
                    animation = new DoubleAnimation
                    {
                        From = -_image.ActualWidth,
                        To = 0,
                        Duration = TimeSpan.FromSeconds(1),
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
                    };

                    Storyboard.SetTargetProperty(animation, "X");
                    break;
                case ImageLoadedTransitionTypes.SlideLeft:
                    animation = new DoubleAnimation
                    {
                        From = _image.ActualWidth,
                        To = 0,
                        Duration = TimeSpan.FromSeconds(1),
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
                    };

                    Storyboard.SetTargetProperty(animation, "X");
                    break;
            }

            Storyboard.SetTarget(animation, tempTransform);
            var sb = new Storyboard();
            sb.Duration = animation.Duration;
            sb.Children.Add(animation);
            var clippingParent = _image.Parent as FrameworkElement;

            RectangleGeometry clip = null;

            if (clippingParent != null)
            {
                clip = clippingParent.Clip;
                var transformToParent = _image.TransformToVisual(clippingParent);
                var topLeft = transformToParent.TransformPoint(new Point(0, 0));
                topLeft = new Point(Math.Max(0, topLeft.X), Math.Max(0, topLeft.Y));
                var bottomRight = transformToParent.TransformPoint(new Point(_image.ActualWidth, _image.ActualHeight));
                bottomRight = new Point(Math.Min(clippingParent.ActualWidth, bottomRight.X), Math.Min(clippingParent.ActualHeight, bottomRight.Y));
                clippingParent.Clip =
                    new RectangleGeometry
                    {
                        Rect = new Rect(
                            topLeft,
                            bottomRight)
                    };
            }

            await sb.BeginAsync();

            if (_image == null)
            {
                return;
            }

            if (clippingParent != null)
            {
                _image.Clip = clip;
            }

            _image.RenderTransform = oldTransform;
        }
        /// <summary>
        /// Translates an element to absolute values
        /// </summary>
        /// <param name="element">Element to translate</param>
        /// <param name="toX">Final X translation</param>
        /// <param name="toY">Final Y translation</param>
        /// <param name="durationInSeconds">Duration in seconds</param>
        /// <param name="OnComplete">[Optional] Action to perform on complete</param>
        /// <returns>Storyboard created</returns>
        public static async Task<Storyboard> TranslateToAsync(this FrameworkElement element, double toX, double toY,
            double durationInSeconds, Action OnComplete = null)
        {
            ValidateForNull(element);
            ValidateCompositeTransform(element);

            Storyboard sb = new Storyboard();

            DoubleAnimation xAnimation = CreateDoubleAnimation(element,
                durationInSeconds, toX,
                "(FrameworkElement.RenderTransform).(CompositeTransform.TranslateX)");


            DoubleAnimation yAnimation = CreateDoubleAnimation(element,
                durationInSeconds, toY,
                "(FrameworkElement.RenderTransform).(CompositeTransform.TranslateY)");

            sb.Children.Add(xAnimation);
            sb.Children.Add(yAnimation);
            await sb.BeginAsync();
            if (OnComplete != null) OnComplete();
            return sb;
        }
        /// <summary>
        /// Fades the element out using a custom DoubleAnimation of the Opacity property.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="duration"></param>
        /// <param name="easingFunction"> </param>
        /// <returns></returns>
        public static async Task FadeOutCustom(this UIElement element, TimeSpan? duration = null, EasingFunctionBase easingFunction = null)
        {
            CleanUpPreviousFadeStoryboard(element); 
            
            var fadeOutStoryboard = new Storyboard();
            var fadeOutAnimation = new DoubleAnimation();

            if (duration == null)
                duration = TimeSpan.FromSeconds(0.4);

            fadeOutAnimation.Duration = duration.Value;
            fadeOutAnimation.To = 0.0;
            fadeOutAnimation.EasingFunction = easingFunction;

            Storyboard.SetTarget(fadeOutAnimation, element);
            Storyboard.SetTargetProperty(fadeOutAnimation, "Opacity");
            fadeOutStoryboard.Children.Add(fadeOutAnimation);
            SetAttachedFadeStoryboard(element, fadeOutStoryboard);
            await fadeOutStoryboard.BeginAsync();
            element.Opacity = 0.0;
            fadeOutStoryboard.Stop();
        } 
        /// <summary>
        /// Runs backward transition.
        /// </summary>
        /// <param name="previousPage">The previous page.</param>
        /// <param name="newPage">The new page.</param>
        /// <returns>The task that completes when the transition is complete.</returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public async Task TransitionBackward(DependencyObject previousPage, DependencyObject newPage)
        {
            if (previousPage == null && newPage == null)
            {
                throw new ArgumentNullException("newPage");
            }

            PrepareBackwardAnimations(previousPage, newPage);

            UpdateTimelineAttributes();

            if (previousPage == null)
            {
                await BackwardInAnimation.Animate(newPage);
            }
            else if (newPage == null)
            {
                await BackwardOutAnimation.Animate(previousPage);
            }
            else if (this.Mode == PageTransitionMode.Parallel)
            {
                var sb = new Storyboard();

                Storyboard outSb = null;
                Storyboard inSb = null;

                if (this.BackwardOutAnimation != null)
                {
                    outSb = this.BackwardOutAnimation.GetAnimation(previousPage);
                    sb.Children.Add(outSb);
                }

                if (this.BackwardInAnimation != null)
                {
                    inSb = this.BackwardInAnimation.GetAnimation(newPage);
                    sb.Children.Add(inSb);
                }
                
                await sb.BeginAsync();
                sb.Stop();
                sb.Children.Clear();

                if (this.BackwardOutAnimation != null)
                {
                    this.BackwardOutAnimation.CleanupAnimation(previousPage, outSb);
                }

                if (this.BackwardInAnimation != null)
                {
                    this.BackwardInAnimation.CleanupAnimation(newPage, inSb);
                }
                //await Task.WhenAll(
                //    BackwardOutAnimation.Animate(previousPage),
                //    BackwardInAnimation.Animate(newPage));
            }
            else
            {
                if (this.BackwardOutAnimation != null)
                {
                    await this.BackwardOutAnimation.Animate(previousPage);
                }

                if (this.BackwardInAnimation != null)
                {
                    await this.BackwardInAnimation.Animate(newPage);
                }
            }

            CleanupBackwardAnimations(previousPage, newPage);
        }