Browse Source

Merge pull request #4061 from AvaloniaUI/fixes/4059-transitions-keynotfound

Fix KeyNotFound exception in Animatable
Jumar Macato 5 years ago
parent
commit
4822e8a610

+ 9 - 7
src/Avalonia.Animation/Animatable.cs

@@ -93,17 +93,17 @@ namespace Avalonia.Animation
                 var oldTransitions = change.OldValue.GetValueOrDefault<Transitions>();
                 var newTransitions = change.NewValue.GetValueOrDefault<Transitions>();
 
-                if (oldTransitions is object)
-                {
-                    oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
-                    RemoveTransitions(oldTransitions);
-                }
-
                 if (newTransitions is object)
                 {
                     newTransitions.CollectionChanged += TransitionsCollectionChanged;
                     AddTransitions(newTransitions);
                 }
+
+                if (oldTransitions is object)
+                {
+                    oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
+                    RemoveTransitions(oldTransitions);
+                }
             }
             else if (_transitionsEnabled &&
                      Transitions is object &&
@@ -111,8 +111,10 @@ namespace Avalonia.Animation
                      !change.Property.IsDirect &&
                      change.Priority > BindingPriority.Animation)
             {
-                foreach (var transition in Transitions)
+                for (var i = Transitions.Count -1; i >= 0; --i)
                 {
+                    var transition = Transitions[i];
+
                     if (transition.Property == change.Property)
                     {
                         var state = _transitionState[transition];

+ 65 - 0
tests/Avalonia.Animation.UnitTests/AnimatableTests.cs

@@ -2,6 +2,7 @@
 using Avalonia.Controls;
 using Avalonia.Data;
 using Avalonia.Layout;
+using Avalonia.Media;
 using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Moq;
@@ -265,6 +266,70 @@ namespace Avalonia.Animation.UnitTests
             }
         }
 
+        [Fact]
+        public void Replacing_Transitions_During_Animation_Does_Not_Throw_KeyNotFound()
+        {
+            // Issue #4059
+            using (UnitTestApplication.Start(TestServices.RealStyler))
+            {
+                Border target;
+                var clock = new TestClock();
+                var root = new TestRoot
+                {
+                    Clock = clock,
+                    Styles =
+                    {
+                        new Style(x => x.OfType<Border>())
+                        {
+                            Setters =
+                            {
+                                new Setter(Border.TransitionsProperty,
+                                    new Transitions
+                                    {
+                                        new DoubleTransition
+                                        {
+                                            Property = Border.OpacityProperty,
+                                            Duration = TimeSpan.FromSeconds(1),
+                                        },
+                                    }),
+                            },
+                        },
+                        new Style(x => x.OfType<Border>().Class("foo"))
+                        {
+                            Setters =
+                            {
+                                new Setter(Border.TransitionsProperty,
+                                    new Transitions
+                                    {
+                                        new DoubleTransition
+                                        {
+                                            Property = Border.OpacityProperty,
+                                            Duration = TimeSpan.FromSeconds(1),
+                                        },
+                                    }),
+                                new Setter(Border.OpacityProperty, 0.0),
+                            },
+                        },
+                    },
+                    Child = target = new Border
+                    {
+                        Background = Brushes.Red,
+                    }
+                };
+
+                root.Measure(Size.Infinity);
+                root.Arrange(new Rect(root.DesiredSize));
+
+                target.Classes.Add("foo");
+                clock.Step(TimeSpan.FromSeconds(0));
+                clock.Step(TimeSpan.FromSeconds(0.5));
+
+                Assert.Equal(0.5, target.Opacity);
+
+                target.Classes.Remove("foo");
+            }
+        }
+
         private static Mock<ITransition> CreateTarget()
         {
             return CreateTransition(Visual.OpacityProperty);