// Manages the fade animation
        private static Task ManageCompositionFadeSlidenimationAsync(this UIElement element,
            float? startOp, float endOp,
            int ms, int? msDelay, EasingFunctionNames easingFunction)
        {
            // Get the default values
            Visual visual = element.GetVisual();
            visual.StopAnimation("Opacity");
            if (!startOp.HasValue) startOp = visual.Opacity;

            // Get the easing function, the duration and delay
            CompositionEasingFunction ease = visual.GetEasingFunction(easingFunction);
            TimeSpan duration = TimeSpan.FromMilliseconds(ms);
            TimeSpan? delay;
            if (msDelay.HasValue) delay = TimeSpan.FromMilliseconds(msDelay.Value);
            else delay = null;

            // Get the opacity the animation
            ScalarKeyFrameAnimation opacityAnimation = visual.Compositor.CreateScalarKeyFrameAnimation(endOp, startOp, duration, delay, ease);

            // Close the batch and manage its event
            CompositionScopedBatch batch = visual.Compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
            batch.Completed += (s, e) => tcs.SetResult(null);
            visual.StartAnimation("Opacity", opacityAnimation);
            batch.End();
            return tcs.Task;
        }
 public static CubicBezierEasingFunction GetEasingFunction(this CompositionObject compObject, EasingFunctionNames ease)
 {
     switch (ease)
     {
         case EasingFunctionNames.Linear: return GetCubicBeizerFunction(compObject, 0, 0, 1, 1);
         case EasingFunctionNames.SineEaseIn: return GetCubicBeizerFunction(compObject, 0.4f, 0, 1, 1);
         case EasingFunctionNames.SineEaseOut: return GetCubicBeizerFunction(compObject, 0, 0, 0.6f, 1);
         case EasingFunctionNames.SineEaseInOut: return GetCubicBeizerFunction(compObject, 0, 0.4f, 0.6f, 1);
         case EasingFunctionNames.QuadraticEaseIn: return GetCubicBeizerFunction(compObject, 0, 0.8f, 1, 1);
         case EasingFunctionNames.QuadraticEaseOut: return GetCubicBeizerFunction(compObject, 0, 0.4f, 0.8f, 1);
         case EasingFunctionNames.QuadraticEaseInOut: return GetCubicBeizerFunction(compObject, 0, 0.6f, 0.3f, 1);
         default: throw new ArgumentOutOfRangeException(nameof(ease), ease, "This shouldn't happen");
     }
 }
        /// <summary>
        /// Converts an easing function name to the right easing function
        /// </summary>
        /// <param name="ease">The desired easing function</param>
        public static EasingFunctionBase ToEasingFunction(this EasingFunctionNames ease)
        {
            switch (ease)
            {
            case EasingFunctionNames.Linear: return(null);

            case EasingFunctionNames.SineEaseIn: return(new SineEase {
                    EasingMode = EasingMode.EaseIn
                });

            case EasingFunctionNames.SineEaseOut: return(new SineEase {
                    EasingMode = EasingMode.EaseOut
                });

            case EasingFunctionNames.SineEaseInOut: return(new SineEase {
                    EasingMode = EasingMode.EaseInOut
                });

            case EasingFunctionNames.QuadraticEaseIn: return(new QuadraticEase {
                    EasingMode = EasingMode.EaseIn
                });

            case EasingFunctionNames.QuadraticEaseOut: return(new QuadraticEase {
                    EasingMode = EasingMode.EaseOut
                });

            case EasingFunctionNames.QuadraticEaseInOut: return(new QuadraticEase {
                    EasingMode = EasingMode.EaseInOut
                });

            case EasingFunctionNames.CircleEaseIn: return(new CircleEase {
                    EasingMode = EasingMode.EaseIn
                });

            case EasingFunctionNames.CircleEaseOut: return(new CircleEase {
                    EasingMode = EasingMode.EaseOut
                });

            case EasingFunctionNames.CircleEaseInOut: return(new CircleEase {
                    EasingMode = EasingMode.EaseInOut
                });

            default: throw new ArgumentOutOfRangeException(nameof(ease), ease, "This shouldn't happen");
            }
        }
        // Manages the fade and slide animation
        private static Task ManageCompositionFadeSlideAnimationAsync(this UIElement element,
            float? startOp, float endOp,
            TranslationAxis axis, float? startXY, float endXY,
            int msOp, int? msSlide, int? msDelay, EasingFunctionNames easingFunction)
        {
            // Get the default values
            Visual visual = element.GetVisual();
            visual.StopAnimation("Opacity");
            visual.StopAnimation("Offset");
            if (!startOp.HasValue) startOp = visual.Opacity;

            // Get the easing function, the duration and delay
            CompositionEasingFunction ease = visual.GetEasingFunction(easingFunction);
            TimeSpan durationOp = TimeSpan.FromMilliseconds(msOp);
            TimeSpan durationSlide = TimeSpan.FromMilliseconds(msSlide ?? msOp);
            TimeSpan? delay;
            if (msDelay.HasValue) delay = TimeSpan.FromMilliseconds(msDelay.Value);
            else delay = null;

            // Calculate the initial and final offset values
            Vector3 initialOffset = visual.Offset;
            Vector3 endOffset = visual.Offset;
            if (axis == TranslationAxis.X)
            {
                if (startXY.HasValue) initialOffset.X = startXY.Value;
                endOffset.X = endXY;
            }
            else
            {
                if (startXY.HasValue) initialOffset.Y = startXY.Value;
                endOffset.Y = endXY;
            }

            // Get the batch
            CompositionScopedBatch batch = visual.Compositor.CreateScopedBatch(CompositionBatchTypes.Animation);

            // Get the opacity the animation
            ScalarKeyFrameAnimation opacityAnimation = visual.Compositor.CreateScalarKeyFrameAnimation(endOp, startOp, durationOp, delay, ease);

            // Offset animation
            Vector3KeyFrameAnimation offsetAnimation = visual.Compositor.CreateVector3KeyFrameAnimation(endOffset, initialOffset, durationSlide, delay, ease);

            // Close the batch and manage its event
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
            batch.Completed += (s, e) => tcs.SetResult(null);
            visual.StartAnimation("Opacity", opacityAnimation);
            visual.StartAnimation("Offset", offsetAnimation);
            batch.End();
            return tcs.Task;
        }
 /// <summary>
 /// Starts a fade animation on the target UIElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
 /// <param name="endOp">The final opacity value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 public static Task StartCompositionFadeAnimationAsync(this UIElement element,
     float? startOp, float endOp,
     int ms, int? msDelay, EasingFunctionNames easingFunction)
 {
     return ManageCompositionFadeSlidenimationAsync(element, startOp, endOp, ms, msDelay, easingFunction);
 }
 /// <summary>
 /// Starts an offset animation on the target FrameworkElement and optionally runs a callback Action when the animations finish
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="axis">The offset axis</param>
 /// <param name="startOffset">The initial offset X and Y value. If null, the current offset will be used</param>
 /// <param name="endOffset">The final offset X and Y value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 /// <param name="callback">An Action to execute when the new animations end</param>
 public static async void StartCompositionSlideAnimation(this FrameworkElement element,
     TranslationAxis axis, float? startOffset, float endOffset,
     int ms, int? msDelay, EasingFunctionNames easingFunction, bool reverse = false, Action callback = null)
 {
     await element.ManageCompositionSlideAnimationAsync(axis, startOffset, endOffset, ms, msDelay, easingFunction);
     callback?.Invoke();
 }
 /// <summary>
 /// Starts a scale animation on the target FrameworkElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startScale">The initial scale X and Y value. If null, the current scale will be used</param>
 /// <param name="endScale">The final scale X and Y value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 public static async Task StartCompositionScaleAnimationAsync(this FrameworkElement element,
     float? startScale, float endScale,
     int ms, int? msDelay, EasingFunctionNames easingFunction, bool reverse = false)
 {
     startScale = await ManageCompositionScaleAnimationAsync(element, startScale, endScale, ms, msDelay, easingFunction);
     if (reverse) await ManageCompositionScaleAnimationAsync(element, endScale, startScale.Value, ms, msDelay, easingFunction);
 }
        // Manages the scale animation
        private static async Task<float> ManageCompositionScaleAnimationAsync(this FrameworkElement element,
            float? startXY, float endXY,
            int ms, int? msDelay, EasingFunctionNames easingFunction)
        {
            // Get the default values and set the CenterPoint
            Visual visual = element.GetVisual();
            visual.StopAnimation("Scale");
            await element.SetCenterPoint(visual);

            // Get the easing function, the duration and delay
            CompositionEasingFunction ease = visual.GetEasingFunction(easingFunction);
            TimeSpan duration = TimeSpan.FromMilliseconds(ms);
            TimeSpan? delay;
            if (msDelay.HasValue) delay = TimeSpan.FromMilliseconds(msDelay.Value);
            else delay = null;

            // Calculate the initial and final scale values
            Vector3 initialScale = visual.Scale;
            if (startXY.HasValue)
            {
                initialScale.X = startXY.Value;
                initialScale.Y = startXY.Value;
            }
            Vector3 endScale = new Vector3
            {
                X = endXY,
                Y = endXY,
                Z = visual.Scale.Z
            };

            // Scale animation
            Vector3KeyFrameAnimation offsetAnimation = visual.Compositor.CreateVector3KeyFrameAnimation(endScale, initialScale, duration, delay, ease);

            // Get the batch and start the animations
            CompositionScopedBatch batch = visual.Compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
            batch.Completed += (s, e) => tcs.SetResult(null);
            visual.StartAnimation("Scale", offsetAnimation);
            batch.End();
            await tcs.Task;
            return initialScale.X;
        }
        /// <summary>
        /// Animates the target color brush to a given color
        /// </summary>
        /// <param name="solidColorBrush">The brush to animate</param>
        /// <param name="toColor">The target color to set</param>
        /// <param name="ms">The duration of the animation</param>
        /// <param name="easing">The easing function to use</param>
        public static void AnimateColor(this SolidColorBrush solidColorBrush, String toColor, int ms, EasingFunctionNames easing)
        {
            // Get the target color
            Color targetColor = ColorConverter.String2Color(toColor);

            if (solidColorBrush.Color.Equals(targetColor))
            {
                return;
            }

            // Prepare the animation
            ColorAnimation animation = new ColorAnimation
            {
                From           = solidColorBrush.Color,
                To             = targetColor,
                Duration       = new Duration(TimeSpan.FromMilliseconds(ms)),
                EasingFunction = easing.ToEasingFunction()
            };

            Storyboard.SetTarget(animation, solidColorBrush);
            Storyboard.SetTargetProperty(animation, "Color");
            Storyboard storyboard = new Storyboard();

            storyboard.Children.Add(animation);
            storyboard.Begin();
        }
        /// <summary>
        /// Slides a target element over a given axis
        /// </summary>
        /// <param name="element">The element to animate</param>
        /// <param name="axis">A String that indicates which axis to use with the TranslateTransform animation</param>
        /// <param name="startXY">The initial axis value</param>
        /// <param name="endXY">The final axis value</param>
        /// <param name="ms">The duration of the animation in milliseconds</param>
        /// <param name="easing">The easing function to use in the animation</param>
        public static Storyboard GetXAMLTransformSlideStoryboard(this UIElement element,
                                                                 TranslationAxis axis, double?startXY, double?endXY, int ms, EasingFunctionNames easing)
        {
            // Try to get the original starting value if necessary
            TranslateTransform translate = element.RenderTransform as TranslateTransform;
            bool cleanAnimation          = startXY != null;

            if (startXY == null && translate != null)
            {
                startXY = axis == TranslationAxis.X ? element.RenderTransform.To <TranslateTransform>().X : element.RenderTransform.To <TranslateTransform>().Y;
            }

            // Prepare and run the animation
            if (translate == null || cleanAnimation)
            {
                translate = new TranslateTransform();
                element.RenderTransform = translate;
            }
            return(XAMLTransformToolkit.PrepareStory(XAMLTransformToolkit.CreateDoubleAnimation(translate, axis.ToPropertyString(), startXY, endXY, ms, easing)));
        }
 /// <summary>
 /// Starts and wait a fade and slide animation on the target UIElement
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="axis">The offset axis to use on the translation animation</param>
 /// <param name="startXY">The initial offset value. If null, the current offset will be used</param>
 /// <param name="endXY">The final offset value</param>
 /// <param name="ms">The duration of the fade animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 public static Task StartXAMLTransformSlideAnimationAsync(this UIElement element,
                                                          TranslationAxis axis, double?startXY, double?endXY,
                                                          int ms, int?msDelay, EasingFunctionNames easingFunction, bool reverse = false)
 {
     return(element.ManageXAMLTransformSlideAnimationAsync(axis, startXY, endXY, ms, msDelay, easingFunction, reverse));
 }
        /// <summary>
        /// Starts a fade and slide animation on the target UIElement and optionally runs a callback Action when the animations finish
        /// </summary>
        /// <param name="element">The UIElement to animate</param>
        /// <param name="axis">The offset axis to use on the translation animation</param>
        /// <param name="startXY">The initial offset value. If null, the current offset will be used</param>
        /// <param name="endXY">The final offset value</param>
        /// <param name="ms">The duration of the animation, in milliseconds</param>
        /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
        /// <param name="easingFunction">The easing function to use with the new animations</param>
        /// <param name="callback">An Action to execute when the new animations end</param>
        /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
        public static async void StartXAMLTransformSlideAnimation(this UIElement element,
                                                                  TranslationAxis axis, double?startXY, double?endXY,
                                                                  int ms, int?msDelay, EasingFunctionNames easingFunction, Action callback = null, bool reverse = false)
        {
            await element.ManageXAMLTransformSlideAnimationAsync(axis, startXY, endXY, ms, msDelay, easingFunction, reverse);

            callback?.Invoke();
        }
        // Manages the scale animation
        private static async Task ManageXAMLTransformFadeScaleAnimationAsync(this UIElement element,
                                                                             double?startScale, double?endScale,
                                                                             int ms, int?msDelay, EasingFunctionNames easingFunction, bool reverse)
        {
            // Delay if necessary
            if (msDelay.HasValue)
            {
                await Task.Delay(msDelay.Value);
            }

            // Try to get the original starting values if necessary
            if (startScale == null && element.RenderTransform is ScaleTransform)
            {
                ScaleTransform scale = element.RenderTransform.To <ScaleTransform>();
                startScale = (scale.ScaleX + scale.ScaleY) / 2;
            }

            // Start and wait the animation
            DoubleAnimation scaleX = XAMLTransformToolkit.CreateDoubleAnimation(element.GetRenderTransform <ScaleTransform>(), "ScaleX",
                                                                                startScale, endScale, ms, easingFunction);
            DoubleAnimation scaleY = XAMLTransformToolkit.CreateDoubleAnimation(element.GetRenderTransform <ScaleTransform>(), "ScaleY",
                                                                                startScale, endScale, ms, easingFunction);
            Storyboard storyboard = XAMLTransformToolkit.PrepareStory(scaleX, scaleY);

            storyboard.AutoReverse = reverse;
            await storyboard.WaitAsync();
        }
        // Manages the fade animation
        private static async Task ManageXAMLTransformFadeAnimationAsync(this UIElement element,
                                                                        double?startOp, double?endOp,
                                                                        int ms, int?msDelay, EasingFunctionNames easingFunction, bool reverse)
        {
            // Delay if necessary
            if (msDelay.HasValue)
            {
                await Task.Delay(msDelay.Value);
            }

            // Start and wait the animation
            DoubleAnimation animation  = XAMLTransformToolkit.CreateDoubleAnimation(element, "Opacity", startOp ?? element.Opacity, endOp, ms, easingFunction);
            Storyboard      storyboard = XAMLTransformToolkit.PrepareStory(animation);

            storyboard.AutoReverse = reverse;
            await storyboard.WaitAsync();
        }
 /// <summary>
 /// Starts a fade and slide animation on the target UIElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
 /// <param name="endOp">The final opacity value</param>
 /// <param name="axis">The offset axis to use on the translation animation</param>
 /// <param name="startXY">The initial offset value. If null, the current offset will be used</param>
 /// <param name="endXY">The final offset value</param>
 /// <param name="msOp">The duration of the fade animation, in milliseconds</param>
 /// <param name="msSlide">The duration of the slide animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 public static Task StartCompositionFadeSlideAnimationAsync(this UIElement element,
     float? startOp, float endOp,
     TranslationAxis axis, float? startXY, float endXY,
     int msOp, int? msSlide, int? msDelay, EasingFunctionNames easingFunction)
 {
     return ManageCompositionFadeSlideAnimationAsync(element, startOp, endOp, axis, startXY, endXY, msOp, msSlide, msDelay, easingFunction);
 }
 /// <summary>
 /// Starts a fade and scale animation on the target FrameworkElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
 /// <param name="endOp">The final opacity value</param>
 /// <param name="startScale">The initial scale X and Y value. If null, the current scale will be used</param>
 /// <param name="endScale">The final scale X and Y value</param>
 /// <param name="msOp">The duration of the fade animation, in milliseconds</param>
 /// <param name="msScale">The duration of the scale animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 public static Task StartCompositionFadeScaleAnimationAsync(this FrameworkElement element,
     float? startOp, float endOp,
     float? startScale, float endScale,
     int msOp, int? msScale, int? msDelay, EasingFunctionNames easingFunction)
 {
     return ManageCompositionFadeScaleAnimationAsync(element, startOp, endOp, startScale, endScale, msOp, msScale, msDelay, easingFunction);
 }
        /// <summary>
        /// Starts a fade animation on the target UIElement and optionally runs a callback Action when the animations finish
        /// </summary>
        /// <param name="element">The UIElement to animate</param>
        /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
        /// <param name="endOp">The final opacity value</param>
        /// <param name="ms">The duration of the animation, in milliseconds</param>
        /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
        /// <param name="easingFunction">The easing function to use with the new animations</param>
        /// <param name="callback">An Action to execute when the new animations end</param>
        /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
        public static async void StartXAMLTransformFadeAnimation(this UIElement element,
                                                                 double?startOp, double?endOp,
                                                                 int ms, int?msDelay, EasingFunctionNames easingFunction, Action callback = null, bool reverse = false)
        {
            await ManageXAMLTransformFadeAnimationAsync(element, startOp, endOp, ms, msDelay, easingFunction, reverse);

            callback?.Invoke();
        }
 /// <summary>
 /// Starts a scale animation on the target FrameworkElement and optionally runs a callback Action when the animations finish
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startScale">The initial scale X and Y value. If null, the current scale will be used</param>
 /// <param name="endScale">The final scale X and Y value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 /// <param name="callback">An Action to execute when the new animations end</param>
 public static async void StartCompositionScaleAnimation(this FrameworkElement element,
     float? startScale, float endScale,
     int ms, int? msDelay, EasingFunctionNames easingFunction, bool reverse = false, Action callback = null)
 {
     await element.StartCompositionScaleAnimationAsync(startScale, endScale, ms, msDelay, easingFunction, reverse);
     callback?.Invoke();
 }
 /// <summary>
 /// Starts a fade animation on the target UIElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
 /// <param name="endOp">The final opacity value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 public static Task StartXAMLTransformFadeAnimationAsync(this UIElement element,
                                                         double?startOp, double?endOp,
                                                         int ms, int?msDelay, EasingFunctionNames easingFunction, bool reverse = false)
 {
     return(ManageXAMLTransformFadeAnimationAsync(element, startOp, endOp, ms, msDelay, easingFunction, reverse));
 }
        // Manages the scale animation
        private static async Task<float> ManageCompositionSlideAnimationAsync(this FrameworkElement element,
            TranslationAxis axis, float? startXY, float endXY,
            int ms, int? msDelay, EasingFunctionNames easingFunction)
        {
            // Get the default values
            Visual visual = element.GetVisual();
            visual.StopAnimation("Offset");

            // Get the easing function, the duration and delay
            CompositionEasingFunction ease = visual.GetEasingFunction(easingFunction);
            TimeSpan duration = TimeSpan.FromMilliseconds(ms);
            TimeSpan? delay;
            if (msDelay.HasValue) delay = TimeSpan.FromMilliseconds(msDelay.Value);
            else delay = null;

            // Calculate the initial and final offset values
            Vector3 initialOffset = visual.Offset;
            Vector3 endOffset = visual.Offset;
            if (axis == TranslationAxis.X)
            {
                if (startXY.HasValue) initialOffset.X = startXY.Value;
                endOffset.X = endXY;
            }
            else
            {
                if (startXY.HasValue) initialOffset.Y = startXY.Value;
                endOffset.Y = endXY;
            }

            // Scale animation
            Vector3KeyFrameAnimation offsetAnimation = visual.Compositor.CreateVector3KeyFrameAnimation(endOffset, initialOffset, duration, delay, ease);

            // Get the batch and start the animations
            CompositionScopedBatch batch = visual.Compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
            batch.Completed += (s, e) => tcs.SetResult(null);
            visual.StartAnimation("Offset", offsetAnimation);
            batch.End();
            await tcs.Task;
            return initialOffset.X;
        }
        // Manages the fade and slide animation
        private static async Task ManageXAMLTransformFadeSlideAnimationAsync(this UIElement element,
                                                                             double?startOp, double?endOp,
                                                                             TranslationAxis axis, double?startXY, double?endXY,
                                                                             int msOp, int?msSlide, int?msDelay, EasingFunctionNames easingFunction, bool reverse)
        {
            // Delay if necessary
            if (msDelay.HasValue)
            {
                await Task.Delay(msDelay.Value);
            }

            // Try to get the original starting value if necessary
            if (startXY == null && element.RenderTransform is TranslateTransform)
            {
                startXY = axis == TranslationAxis.X ? element.RenderTransform.To <TranslateTransform>().X : element.RenderTransform.To <TranslateTransform>().Y;
            }

            // Start and wait the animation
            DoubleAnimation opacity = XAMLTransformToolkit.CreateDoubleAnimation(element, "Opacity", startOp ?? element.Opacity, endOp, msOp, easingFunction);
            DoubleAnimation slide   = XAMLTransformToolkit.CreateDoubleAnimation(element.GetRenderTransform <TranslateTransform>(),
                                                                                 axis.ToPropertyString(), startXY, endXY,
                                                                                 msSlide ?? msOp, easingFunction);
            Storyboard storyboard = XAMLTransformToolkit.PrepareStory(opacity, slide);

            storyboard.AutoReverse = reverse;
            await storyboard.WaitAsync();
        }
 /// <summary>
 /// Starts an offset animation on the target FrameworkElement and returns a Task that completes when the animation ends
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="axis">The offset axis</param>
 /// <param name="startOffset">The initial offset X and Y value. If null, the current offset will be used</param>
 /// <param name="endOffset">The final offset X and Y value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param>
 public static async Task StartCompositionSlideAnimationAsync(this FrameworkElement element,
     TranslationAxis axis, float? startOffset, float endOffset,
     int ms, int? msDelay, EasingFunctionNames easingFunction, bool reverse = false)
 {
     startOffset = await element.ManageCompositionSlideAnimationAsync(axis, startOffset, endOffset, ms, msDelay, easingFunction);
     if (reverse) await element.ManageCompositionSlideAnimationAsync(axis, endOffset, startOffset.Value, ms, msDelay, easingFunction);
 }
Exemplo n.º 23
0
        /// <summary>
        /// Prepares a an animation with the given info
        /// </summary>
        /// <param name="target">The target object to animate</param>
        /// <param name="property">The property to animate inside the target object</param>
        /// <param name="from">The initial property value</param>
        /// <param name="to">The final property value</param>
        /// <param name="ms">The duration of the animation</param>
        /// <param name="easing">The easing function to use inside the animation</param>
        /// <param name="enableDependecyAnimations">Indicates whether or not to apply this animation to elements that need the visual tree to be rearranged</param>
        public static DoubleAnimation CreateDoubleAnimation(DependencyObject target, String property,
                                                            double?from, double?to, int ms, EasingFunctionNames easing = EasingFunctionNames.Linear, bool enableDependecyAnimations = false)
        {
            DoubleAnimation animation = new DoubleAnimation
            {
                From     = from,
                To       = to,
                Duration = new Duration(TimeSpan.FromMilliseconds(ms)),
                EnableDependentAnimation = enableDependecyAnimations
            };

            if (easing != EasingFunctionNames.Linear)
            {
                animation.EasingFunction = easing.ToEasingFunction();
            }
            Storyboard.SetTarget(animation, target);
            Storyboard.SetTargetProperty(animation, property);
            return(animation);
        }
 /// <summary>
 /// Starts a fade animation on the target UIElement and optionally runs a callback Action when the animations finish
 /// </summary>
 /// <param name="element">The UIElement to animate</param>
 /// <param name="startOp">The initial opacity value. If null, the current opacity will be used</param>
 /// <param name="endOp">The final opacity value</param>
 /// <param name="ms">The duration of the animation, in milliseconds</param>
 /// <param name="msDelay">The delay before the animation starts, in milliseconds. If null, there will be no delay</param>
 /// <param name="easingFunction">The easing function to use with the new animations</param>
 /// <param name="callback">An Action to execute when the new animations end</param>
 public static async void StartCompositionFadeAnimation(this UIElement element,
     float? startOp, float endOp,
     int ms, int? msDelay, EasingFunctionNames easingFunction, Action callback = null)
 {
     await ManageCompositionFadeSlidenimationAsync(element, startOp, endOp, ms, msDelay, easingFunction);
     callback?.Invoke();
 }
        public static CubicBezierEasingFunction GetEasingFunction(this CompositionObject compObject, EasingFunctionNames ease)
        {
            switch (ease)
            {
            case EasingFunctionNames.Linear: return(GetCubicBeizerFunction(compObject, 0, 0, 1, 1));

            case EasingFunctionNames.SineEaseIn: return(GetCubicBeizerFunction(compObject, 0.4f, 0, 1, 1));

            case EasingFunctionNames.SineEaseOut: return(GetCubicBeizerFunction(compObject, 0, 0, 0.6f, 1));

            case EasingFunctionNames.SineEaseInOut: return(GetCubicBeizerFunction(compObject, 0.4f, 0, 0.6f, 1));

            case EasingFunctionNames.QuadraticEaseIn: return(GetCubicBeizerFunction(compObject, 0.8f, 0, 1, 1));

            case EasingFunctionNames.QuadraticEaseOut: return(GetCubicBeizerFunction(compObject, 0, 0, 0.2f, 1));

            case EasingFunctionNames.QuadraticEaseInOut: return(GetCubicBeizerFunction(compObject, 0.8f, 0, 0.2f, 1));

            case EasingFunctionNames.CircleEaseIn: return(GetCubicBeizerFunction(compObject, 1, 0, 1, 0.8f));

            case EasingFunctionNames.CircleEaseOut: return(GetCubicBeizerFunction(compObject, 0, 0.3f, 0, 1));

            case EasingFunctionNames.CircleEaseInOut: return(GetCubicBeizerFunction(compObject, 0.9f, 0, 0.1f, 1));

            default: throw new ArgumentOutOfRangeException(nameof(ease), ease, "This shouldn't happen");
            }
        }