// 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 and wait a fade and slide animation on the target UIElement /// </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> /// <param name="reverse">If true, the animation will be played in reverse mode when it finishes for the first time</param> public static Task StartXAMLTransformFadeSlideAnimationAsync(this UIElement element, double?startOp, double?endOp, TranslationAxis axis, double?startXY, double?endXY, int msOp, int?msSlide, int?msDelay, EasingFunctionNames easingFunction, bool reverse = false) { return(element.ManageXAMLTransformFadeSlideAnimationAsync(startOp, endOp, axis, startXY, endXY, msOp, msSlide, 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(); }
/// <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> /// Sets the offset value of a given UIElement /// </summary> /// <param name="element">The UIElement to edit</param> /// <param name="axis">The offset axis to set</param> /// <param name="value">The new value for the axis to set</param> public static void SetVisualOffset(this UIElement element, TranslationAxis axis, float value) { Visual visual = element.GetVisual(); Task.Run(() => { Vector3 offset = visual.Offset; if (axis == TranslationAxis.X) offset.X = value; else offset.Y = value; visual.Offset = offset; }); }
/// <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); }
/// <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(); }
// 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; }
/// <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 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="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> /// <param name="callback">An Action to execute when the new animations end</param> public static async void StartCompositionFadeSlideAnimation(this UIElement element, float? startOp, float endOp, TranslationAxis axis, float? startXY, float endXY, int msOp, int? msSlide, int? msDelay, EasingFunctionNames easingFunction, Action callback = null) { await ManageCompositionFadeSlideAnimationAsync(element, startOp, endOp, axis, startXY, endXY, msOp, msSlide, msDelay, easingFunction); callback?.Invoke(); }
// 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> /// Converts the given TranslationAxis enum into its String representation /// </summary> /// <param name="axis">The enum to convert</param> public static String ToPropertyString(this TranslationAxis axis) => axis == TranslationAxis.X ? "X" : "Y";