diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Media_Animation/Given_Storyboard.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Media_Animation/Given_Storyboard.cs index e7b04bd44042..3457fa8d2de8 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Media_Animation/Given_Storyboard.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Media_Animation/Given_Storyboard.cs @@ -50,4 +50,71 @@ public async Task When_Empty_Storyboard_Paused() Assert.AreEqual(ClockState.Active, storyboard.GetCurrentState()); await TestServices.WindowHelper.WaitFor(() => completed); } + + [TestMethod] + public async Task When_DependentAnimation_Without_EnableDependentAnimation_Completes() + { + var border = new Microsoft.UI.Xaml.Controls.Border + { + Width = 100, + Height = 100 + }; + + var animation = new DoubleAnimation + { + From = 100, + To = 200, + Duration = new Duration(System.TimeSpan.FromMilliseconds(100)), + EnableDependentAnimation = false // Explicitly set to false + }; + + Storyboard.SetTarget(animation, border); + Storyboard.SetTargetProperty(animation, "Height"); + + var storyboard = new Storyboard(); + storyboard.Children.Add(animation); + + bool completed = false; + storyboard.Completed += (s, e) => completed = true; + + storyboard.Begin(); + + // The Completed event should fire even though the animation doesn't actually run + await TestServices.WindowHelper.WaitFor(() => completed, timeoutMS: 2000); + Assert.IsTrue(completed, "Storyboard.Completed should fire even for dependent animations without EnableDependentAnimation"); + } + + [TestMethod] + public async Task When_DependentAnimation_Stopped_Before_Completion() + { + var border = new Microsoft.UI.Xaml.Controls.Border + { + Width = 100, + Height = 100 + }; + + var animation = new DoubleAnimation + { + From = 100, + To = 200, + Duration = new Duration(System.TimeSpan.FromMilliseconds(100)), + EnableDependentAnimation = false + }; + + Storyboard.SetTarget(animation, border); + Storyboard.SetTargetProperty(animation, "Height"); + + var storyboard = new Storyboard(); + storyboard.Children.Add(animation); + + bool completed = false; + storyboard.Completed += (s, e) => completed = true; + + storyboard.Begin(); + storyboard.Stop(); // Stop immediately + + // Completed should not fire when stopped before completion + await TestServices.WindowHelper.WaitForIdle(); + Assert.IsFalse(completed, "Storyboard.Completed should not fire when stopped before completion"); + } } diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.cs b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.cs index 122b59d0357d..123e8e96d9b4 100644 --- a/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.cs +++ b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.cs @@ -244,6 +244,17 @@ private void Play() if (!EnableDependentAnimation && this.GetIsDependantAnimation()) { // Don't start the animator its a dependent animation + // However, we still need to complete the animation to maintain consistency with WinUI + State = TimelineState.Active; + _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + if (State == TimelineState.Stopped) + { + // If the animation was force-stopped, don't trigger completion + return; + } + OnEnd(); + }); return; } diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs index 70335927dc90..5b13fad2da69 100644 --- a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs +++ b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs @@ -214,6 +214,17 @@ private void Play() if (!EnableDependentAnimation && this.GetIsDependantAnimation()) { // Don't start the animator its a dependent animation + // However, we still need to complete the animation to maintain consistency with WinUI + State = TimelineState.Active; + _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + if (State == TimelineState.Stopped) + { + // If the animation was force-stopped, don't trigger completion + return; + } + OnEnd(); + }); return; } diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.cs b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.cs index 4fff4c4a2eaa..015928967b84 100644 --- a/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.cs +++ b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.cs @@ -284,6 +284,17 @@ private void Play() if (!EnableDependentAnimation && _owner.GetIsDependantAnimation()) { // Don't start the animator its a dependent animation + // However, we still need to complete the animation to maintain consistency with WinUI + State = TimelineState.Active; + _ = _owner.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + if (State == TimelineState.Stopped) + { + // If the animation was force-stopped, don't trigger completion + return; + } + OnEnd(); + }); return; }