diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Implicit.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Implicit.cs
index 93c799013e8..61cfb365389 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Implicit.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Implicit.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Windows.Foundation.Collections;
+using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
@@ -130,30 +130,30 @@ public static void SetAnimations(UIElement element, ImplicitAnimationSet value)
/// The instance for the current event.
private static void OnShowAnimationsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- static void OnAnimationsChanged(IObservableVector sender, IVectorChangedEventArgs args)
+ static void OnAnimationsChanged(object sender, EventArgs e)
{
var collection = (ImplicitAnimationSet)sender;
if (collection.ParentReference!.TryGetTarget(out UIElement element))
{
- ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup());
+ ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup(element));
}
}
if (e.OldValue is ImplicitAnimationSet oldCollection)
{
- oldCollection.VectorChanged -= OnAnimationsChanged;
+ oldCollection.AnimationsChanged -= OnAnimationsChanged;
}
if (d is UIElement element &&
e.NewValue is ImplicitAnimationSet collection)
{
collection.ParentReference = new(element);
- collection.VectorChanged -= OnAnimationsChanged;
- collection.VectorChanged += OnAnimationsChanged;
+ collection.AnimationsChanged -= OnAnimationsChanged;
+ collection.AnimationsChanged += OnAnimationsChanged;
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
- ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup());
+ ElementCompositionPreview.SetImplicitShowAnimation(element, collection.GetCompositionAnimationGroup(element));
}
}
@@ -164,30 +164,30 @@ static void OnAnimationsChanged(IObservableVector sender, IVec
/// The instance for the current event.
private static void OnHideAnimationsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- static void OnAnimationsChanged(IObservableVector sender, IVectorChangedEventArgs args)
+ static void OnAnimationsChanged(object sender, EventArgs e)
{
var collection = (ImplicitAnimationSet)sender;
if (collection.ParentReference!.TryGetTarget(out UIElement element))
{
- ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup());
+ ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup(element));
}
}
if (e.OldValue is ImplicitAnimationSet oldCollection)
{
- oldCollection.VectorChanged -= OnAnimationsChanged;
+ oldCollection.AnimationsChanged -= OnAnimationsChanged;
}
if (d is UIElement element &&
e.NewValue is ImplicitAnimationSet collection)
{
collection.ParentReference = new(element);
- collection.VectorChanged -= OnAnimationsChanged;
- collection.VectorChanged += OnAnimationsChanged;
+ collection.AnimationsChanged -= OnAnimationsChanged;
+ collection.AnimationsChanged += OnAnimationsChanged;
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
- ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup());
+ ElementCompositionPreview.SetImplicitHideAnimation(element, collection.GetCompositionAnimationGroup(element));
}
}
@@ -198,30 +198,30 @@ static void OnAnimationsChanged(IObservableVector sender, IVec
/// The instance for the current event.
private static void OnAnimationsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- static void OnAnimationsChanged(IObservableVector sender, IVectorChangedEventArgs args)
+ static void OnAnimationsChanged(object sender, EventArgs e)
{
var collection = (ImplicitAnimationSet)sender;
if (collection.ParentReference!.TryGetTarget(out UIElement element))
{
- ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection();
+ ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection(element);
}
}
if (e.OldValue is ImplicitAnimationSet oldCollection)
{
- oldCollection.VectorChanged -= OnAnimationsChanged;
+ oldCollection.AnimationsChanged -= OnAnimationsChanged;
}
if (d is UIElement element &&
e.NewValue is ImplicitAnimationSet collection)
{
collection.ParentReference = new(element);
- collection.VectorChanged -= OnAnimationsChanged;
- collection.VectorChanged += OnAnimationsChanged;
+ collection.AnimationsChanged -= OnAnimationsChanged;
+ collection.AnimationsChanged += OnAnimationsChanged;
ElementCompositionPreview.SetIsTranslationEnabled(element, true);
- ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection();
+ ElementCompositionPreview.GetElementVisual(element).ImplicitAnimations = collection.GetImplicitAnimationCollection(element);
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/Animation.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/Animation.cs
index 210e3828d5a..40df464bd8b 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/Animation.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/Animation.cs
@@ -91,14 +91,14 @@ public EasingMode? EasingMode
///
public RepeatOption Repeat
{
- get => (RepeatOption)GetValue(RepeatOptionProperty);
- set => SetValue(RepeatOptionProperty, value);
+ get => (RepeatOption)GetValue(RepeatProperty);
+ set => SetValue(RepeatProperty, value);
}
///
/// Identifies the dependency property.
///
- public static readonly DependencyProperty RepeatOptionProperty = DependencyProperty.Register(
+ public static readonly DependencyProperty RepeatProperty = DependencyProperty.Register(
nameof(Repeat),
typeof(RepeatOption),
typeof(Animation),
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/ImplicitAnimation{TValue,TKeyFrame}.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/ImplicitAnimation{TValue,TKeyFrame}.cs
index 3f9ffc479ec..ac13e522558 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/ImplicitAnimation{TValue,TKeyFrame}.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Abstract/ImplicitAnimation{TValue,TKeyFrame}.cs
@@ -4,6 +4,7 @@
#nullable enable
+using System;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using static Microsoft.Toolkit.Uwp.UI.Animations.AnimationExtensions;
@@ -17,6 +18,25 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
public abstract class ImplicitAnimation : Animation, IImplicitTimeline
where TKeyFrame : unmanaged
{
+ ///
+ public event EventHandler? AnimationPropertyChanged;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected ImplicitAnimation()
+ {
+ RegisterPropertyChangedCallback(DelayProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(DurationProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(EasingTypeProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(EasingModeProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(RepeatProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(DelayBehaviorProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(ToProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(FromProperty, RaiseAnimationPropertyChanged);
+ RegisterPropertyChangedCallback(KeyFramesProperty, RaiseAnimationPropertyChanged);
+ }
+
///
/// Gets or sets the optional implicit target for the animation. This can act as a trigger property for the animation.
///
@@ -67,5 +87,15 @@ public CompositionAnimation GetAnimation(UIElement element, out string? target)
return builder.GetAnimation(element.GetVisual(), out _);
}
+
+ ///
+ /// Raises the event.
+ ///
+ /// The instance raising the event.
+ /// The that was changed.
+ private void RaiseAnimationPropertyChanged(DependencyObject sender, DependencyProperty property)
+ {
+ AnimationPropertyChanged?.Invoke(this, EventArgs.Empty);
+ }
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/ImplicitAnimationSet.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/ImplicitAnimationSet.cs
index eda7836e7f4..b6eb2f259f9 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/ImplicitAnimationSet.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/ImplicitAnimationSet.cs
@@ -6,6 +6,7 @@
using System;
using System.Diagnostics.Contracts;
+using Windows.Foundation.Collections;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
@@ -13,11 +14,73 @@
namespace Microsoft.Toolkit.Uwp.UI.Animations
{
///
- /// A collection of implicit animations that can be grouped together. This type represents a composite animation
- /// (such as ) that is executed on a given element.
+ /// A collection of implicit animations that can be assigned to a and configured to be run automatically
+ /// when the element is either shown or hidden (through and ),
+ /// or whenever one of the targeted properties on the underlying element changes (through ).
+ ///
+ /// Animations within an should be objects implementing the interface, such as
+ /// types inheriting from (eg. , ,
+ /// and , or custom ones such as and ).
+ /// Adding incompatible elements cannot be validated at build-time, but will result in a runtime crash.
+ ///
+ ///
+ /// Animations will monitor for changes in real-time to any of their public properties. For instance, if a binding is used to dynamically update the
+ /// or properties, the entire animation set will be
+ /// initialized again and assigned to the underlying object for the targeted . This does not currently apply
+ /// to changes to the property though (other than the entire property being reassigned). To achieve
+ /// dynamic updates to animation sets in that case, either leverage expression keyframes or just use code-behind to manually reinitialize the animations.
+ ///
///
+ ///
+ /// An instance can only be used on a single target, and it cannot be shared across multiple
+ /// elements. Attempting to do so will result in a runtime crash. Furthermore, it is recommended not to move instances from
+ /// one to another, and doing so will add unnecessary runtime overhead over time. If you want to apply the same animations
+ /// to multiple elements, simply create another instance and another set of animations with the same properties within it.
+ ///
public sealed class ImplicitAnimationSet : DependencyObjectCollection
{
+ ///
+ /// Raised whenever any configuration change occurrs within the current instance.
+ ///
+ internal event EventHandler? AnimationsChanged;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ImplicitAnimationSet()
+ {
+ VectorChanged += ImplicitAnimationSetVectorChanged;
+ }
+
+ ///
+ /// Registers for every added animation.
+ ///
+ /// The current vector of animations.
+ /// The instance for the current event.
+ private void ImplicitAnimationSetVectorChanged(IObservableVector sender, IVectorChangedEventArgs @event)
+ {
+ if (@event.CollectionChange == CollectionChange.ItemInserted ||
+ @event.CollectionChange == CollectionChange.ItemChanged)
+ {
+ IImplicitTimeline item = (IImplicitTimeline)sender[(int)@event.Index];
+
+ item.AnimationPropertyChanged -= RaiseAnimationsChanged;
+ item.AnimationPropertyChanged += RaiseAnimationsChanged;
+ }
+
+ AnimationsChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// The instance raising the event.
+ /// The empty for the event.
+ private void RaiseAnimationsChanged(object sender, EventArgs e)
+ {
+ AnimationsChanged?.Invoke(this, e);
+ }
+
///
/// Gets or sets the weak reference to the parent that owns the current implicit animation collection.
///
@@ -27,11 +90,11 @@ public sealed class ImplicitAnimationSet : DependencyObjectCollection
/// Creates a for the current collection.
/// This can be used to be assigned to show/hide implicit composition animations.
///
+ /// The target to which the animations are being applied to.
/// The instance to use.
[Pure]
- internal CompositionAnimationGroup GetCompositionAnimationGroup()
+ internal CompositionAnimationGroup GetCompositionAnimationGroup(UIElement parent)
{
- UIElement parent = GetParent();
Compositor compositor = ElementCompositionPreview.GetElementVisual(parent).Compositor;
CompositionAnimationGroup animations = compositor.CreateAnimationGroup();
@@ -47,11 +110,11 @@ internal CompositionAnimationGroup GetCompositionAnimationGroup()
/// Creates an for the current collection.
/// This can be used to be assigned to implicit composition animations.
///
+ /// The target to which the animations are being applied to.
/// The instance to use.
[Pure]
- internal ImplicitAnimationCollection GetImplicitAnimationCollection()
+ internal ImplicitAnimationCollection GetImplicitAnimationCollection(UIElement parent)
{
- UIElement parent = GetParent();
Compositor compositor = ElementCompositionPreview.GetElementVisual(parent).Compositor;
ImplicitAnimationCollection animations = compositor.CreateImplicitAnimationCollection();
@@ -71,25 +134,5 @@ internal ImplicitAnimationCollection GetImplicitAnimationCollection()
return animations;
}
-
- ///
- /// Gets the current parent instance.
- ///
- /// The reference from .
- /// Thrown if there is no parent available.
- [Pure]
- private UIElement GetParent()
- {
- UIElement? parent = null;
-
- if (ParentReference?.TryGetTarget(out parent) != true)
- {
- ThrowInvalidOperationException();
- }
-
- return parent!;
-
- static void ThrowInvalidOperationException() => throw new InvalidOperationException("The current ImplicitAnimationSet object isn't bound to a parent UIElement instance.");
- }
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Interfaces/IImplicitTimeline.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Interfaces/IImplicitTimeline.cs
index 963e07bd19e..c4aa6dd2dec 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Interfaces/IImplicitTimeline.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Xaml/Interfaces/IImplicitTimeline.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using Windows.UI.Composition;
using Windows.UI.Xaml;
@@ -14,6 +15,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
///
public interface IImplicitTimeline
{
+ ///
+ /// Raised whenever a property that influences the animation changes.
+ /// This event is used by to update the animations collection
+ /// assigned to a target when any of the individual animations is modified.
+ ///
+ event EventHandler? AnimationPropertyChanged;
+
///
/// Gets a from the current node. This animation might
/// be used either as an implicit show/hide animation, or as a direct implicit animation.