瀏覽代碼

Merge branch 'master' into fixes/3148-virtualization-out-of-range

Steven Kirk 6 年之前
父節點
當前提交
28b071ee19

+ 1 - 0
src/Avalonia.Animation/Properties/AssemblyInfo.cs

@@ -10,3 +10,4 @@ using System.Runtime.CompilerServices;
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")]
 
 
 [assembly: InternalsVisibleTo("Avalonia.LeakTests")]
 [assembly: InternalsVisibleTo("Avalonia.LeakTests")]
+[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")]

+ 1 - 1
src/Avalonia.Animation/TransitionInstance.cs

@@ -28,7 +28,7 @@ namespace Avalonia.Animation
 
 
         private void TimerTick(TimeSpan t)
         private void TimerTick(TimeSpan t)
         {
         {
-            var interpVal = (double)t.Ticks / _duration.Ticks;
+            var interpVal = _duration.Ticks == 0 ? 1d : (double)t.Ticks / _duration.Ticks;
 
 
             // Clamp interpolation value.
             // Clamp interpolation value.
             if (interpVal >= 1d | interpVal < 0d)
             if (interpVal >= 1d | interpVal < 0d)

+ 6 - 6
src/Avalonia.Base/ValueStore.cs

@@ -57,7 +57,8 @@ namespace Avalonia
                 {
                 {
                     if (priority == (int)BindingPriority.LocalValue)
                     if (priority == (int)BindingPriority.LocalValue)
                     {
                     {
-                        _propertyValues.SetValue(property, Validate(property, value));
+                        Validate(property, ref value);
+                        _propertyValues.SetValue(property, value);
                         Changed(property, priority, v, value);
                         Changed(property, priority, v, value);
                         return;
                         return;
                     }
                     }
@@ -78,7 +79,8 @@ namespace Avalonia
 
 
                 if (priority == (int)BindingPriority.LocalValue)
                 if (priority == (int)BindingPriority.LocalValue)
                 {
                 {
-                    _propertyValues.AddValue(property, Validate(property, value));
+                    Validate(property, ref value);
+                    _propertyValues.AddValue(property, value);
                     Changed(property, priority, AvaloniaProperty.UnsetValue, value);
                     Changed(property, priority, AvaloniaProperty.UnsetValue, value);
                     return;
                     return;
                 }
                 }
@@ -166,16 +168,14 @@ namespace Avalonia
                 validate2);
                 validate2);
         }
         }
 
 
-        private object Validate(AvaloniaProperty property, object value)
+        private void Validate(AvaloniaProperty property, ref object value)
         {
         {
             var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(_owner.GetType());
             var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(_owner.GetType());
 
 
             if (validate != null && value != AvaloniaProperty.UnsetValue)
             if (validate != null && value != AvaloniaProperty.UnsetValue)
             {
             {
-                return validate(_owner, value);
+                value = validate(_owner, value);
             }
             }
-
-            return value;
         }
         }
 
 
         private DeferredSetter<T> GetDeferredSetter<T>(AvaloniaProperty property)
         private DeferredSetter<T> GetDeferredSetter<T>(AvaloniaProperty property)

+ 9 - 3
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@@ -1097,9 +1097,15 @@ namespace Avalonia.Controls.Primitives
                 }
                 }
                 else
                 else
                 {
                 {
-                    SelectedIndex = _updateSelectedIndex != int.MinValue ?
-                        _updateSelectedIndex :
-                        AlwaysSelected ? 0 : -1;
+                    if (_updateSelectedIndex != int.MinValue)
+                    {
+                        SelectedIndex = _updateSelectedIndex;
+                    }
+
+                    if (AlwaysSelected && SelectedIndex == -1)
+                    {
+                        SelectedIndex = 0;
+                    }
                 }
                 }
             }
             }
         }
         }

+ 1 - 1
src/Avalonia.Input/Pointer.cs

@@ -37,7 +37,7 @@ namespace Avalonia.Input
         {
         {
             if (Captured != null)
             if (Captured != null)
                 Captured.DetachedFromVisualTree -= OnCaptureDetached;
                 Captured.DetachedFromVisualTree -= OnCaptureDetached;
-            var oldCapture = control;
+            var oldCapture = Captured;
             Captured = control;
             Captured = control;
             PlatformCapture(control);
             PlatformCapture(control);
             if (oldCapture != null)
             if (oldCapture != null)

+ 21 - 7
tests/Avalonia.Animation.UnitTests/TransitionsTests.cs

@@ -1,14 +1,7 @@
 using System;
 using System;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Animation;
 using Avalonia.Controls;
 using Avalonia.Controls;
-using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Avalonia.UnitTests;
-using Avalonia.Data;
 using Xunit;
 using Xunit;
-using Avalonia.Animation.Easings;
 
 
 namespace Avalonia.Animation.UnitTests
 namespace Avalonia.Animation.UnitTests
 {
 {
@@ -69,5 +62,26 @@ namespace Avalonia.Animation.UnitTests
                 Assert.Equal(0, border.Opacity);
                 Assert.Equal(0, border.Opacity);
             }
             }
         }
         }
+
+        [Fact]
+        public void TransitionInstance_With_Zero_Duration_Is_Completed_On_First_Tick()
+        {
+            var clock = new MockGlobalClock();
+
+            using (UnitTestApplication.Start(new TestServices(globalClock: clock)))
+            {
+                int i = 0;
+                var inst = new TransitionInstance(clock, TimeSpan.Zero).Subscribe(nextValue =>
+                {
+                    switch (i++)
+                    {
+                        case 0: Assert.Equal(0, nextValue); break;
+                        case 1: Assert.Equal(1d, nextValue); break;
+                    }
+                });
+
+                clock.Pulse(TimeSpan.FromMilliseconds(10));
+            }
+        }
     }
     }
 }
 }

+ 12 - 0
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs

@@ -78,6 +78,18 @@ namespace Avalonia.Base.UnitTests
             Assert.Equal(10, target.GetValue(Class1.AttachedProperty));
             Assert.Equal(10, target.GetValue(Class1.AttachedProperty));
         }
         }
 
 
+        [Fact]
+        public void PropertyChanged_Event_Uses_Coerced_Value()
+        {
+            var inst = new Class1();
+            inst.PropertyChanged += (sender, e) =>
+            {
+                Assert.Equal(10, e.NewValue);
+            };
+
+            inst.SetValue(Class1.QuxProperty, 15);
+        }
+
         private class Class1 : AvaloniaObject
         private class Class1 : AvaloniaObject
         {
         {
             public static readonly StyledProperty<int> QuxProperty =
             public static readonly StyledProperty<int> QuxProperty =

+ 126 - 2
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@@ -25,7 +25,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
     public class SelectingItemsControlTests
     public class SelectingItemsControlTests
     {
     {
         private MouseTestHelper _helper = new MouseTestHelper();
         private MouseTestHelper _helper = new MouseTestHelper();
-        
+
         [Fact]
         [Fact]
         public void SelectedIndex_Should_Initially_Be_Minus_1()
         public void SelectedIndex_Should_Initially_Be_Minus_1()
         {
         {
@@ -170,6 +170,130 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal("B", listBox.SelectedItem);
             Assert.Equal("B", listBox.SelectedItem);
         }
         }
 
 
+        [Fact]
+        public void Setting_SelectedIndex_Before_Initialize_Should_Retain()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Single,
+                Items = new[] { "foo", "bar", "baz" },
+                SelectedIndex = 1
+            };
+
+            listBox.BeginInit();
+
+            listBox.EndInit();
+
+            Assert.Equal(1, listBox.SelectedIndex);
+            Assert.Equal("bar", listBox.SelectedItem);
+        }
+
+        [Fact]
+        public void Setting_SelectedIndex_During_Initialize_Should_Take_Priority_Over_Previous_Value()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Single,
+                Items = new[] { "foo", "bar", "baz" },
+                SelectedIndex = 2
+            };
+
+            listBox.BeginInit();
+
+            listBox.SelectedIndex = 1;
+
+            listBox.EndInit();
+
+            Assert.Equal(1, listBox.SelectedIndex);
+            Assert.Equal("bar", listBox.SelectedItem);
+        }
+
+        [Fact]
+        public void Setting_SelectedItem_Before_Initialize_Should_Retain()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Single,
+                Items = new[] { "foo", "bar", "baz" },
+                SelectedItem = "bar"
+            };
+
+            listBox.BeginInit();
+
+            listBox.EndInit();
+
+            Assert.Equal(1, listBox.SelectedIndex);
+            Assert.Equal("bar", listBox.SelectedItem);
+        }
+
+
+        [Fact]
+        public void Setting_SelectedItems_Before_Initialize_Should_Retain()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Multiple,
+                Items = new[] { "foo", "bar", "baz" },
+            };
+
+            var selected = new[] { "foo", "bar" };
+
+            foreach (var v in selected)
+            {
+                listBox.SelectedItems.Add(v);
+            }
+
+            listBox.BeginInit();
+
+            listBox.EndInit();
+
+            Assert.Equal(selected, listBox.SelectedItems);
+        }
+
+        [Fact]
+        public void Setting_SelectedItems_During_Initialize_Should_Take_Priority_Over_Previous_Value()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Multiple,
+                Items = new[] { "foo", "bar", "baz" },
+            };
+
+            var selected = new[] { "foo", "bar" };
+
+            foreach (var v in new[] { "bar", "baz" })
+            {
+                listBox.SelectedItems.Add(v);
+            }
+
+            listBox.BeginInit();
+
+            listBox.SelectedItems = new AvaloniaList<object>(selected);
+
+            listBox.EndInit();
+
+            Assert.Equal(selected, listBox.SelectedItems);
+        }
+
+        [Fact]
+        public void Setting_SelectedIndex_Before_Initialize_With_AlwaysSelected_Should_Retain()
+        {
+            var listBox = new ListBox
+            {
+                SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected,
+
+                Items = new[] { "foo", "bar", "baz" },
+                SelectedIndex = 1
+            };
+
+            listBox.BeginInit();
+
+            listBox.EndInit();
+
+            Assert.Equal(1, listBox.SelectedIndex);
+            Assert.Equal("bar", listBox.SelectedItem);
+        }
+
         [Fact]
         [Fact]
         public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
         public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
         {
         {
@@ -851,7 +975,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             var target = new ListBox
             var target = new ListBox
             {
             {
                 Template = Template(),
                 Template = Template(),
-                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz"},
+                Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
             };
             };
 
 
             target.ApplyTemplate();
             target.ApplyTemplate();

+ 39 - 0
tests/Avalonia.Input.UnitTests/PointerTests.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Controls;
+using Avalonia.UnitTests;
+using Avalonia.VisualTree;
+using Xunit;
+
+namespace Avalonia.Input.UnitTests
+{
+    public class PointerTests
+    {
+        [Fact]
+        public void On_Capture_Transfer_PointerCaptureLost_Should_Propagate_Up_To_The_Common_Parent()
+        {
+            Border initialParent, initialCapture, newParent, newCapture;
+            var el = new StackPanel
+            {
+                Children =
+                {
+                    (initialParent = new Border { Child = initialCapture = new Border() }),
+                    (newParent = new Border { Child = newCapture = new Border() })
+                }
+            };
+            var receivers = new List<object>();
+            var root = new TestRoot(el);
+            foreach (InputElement d in root.GetSelfAndVisualDescendants())
+                d.PointerCaptureLost += (s, e) => receivers.Add(s);
+            var pointer = new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
+            
+            pointer.Capture(initialCapture);
+            pointer.Capture(newCapture);
+            Assert.True(receivers.SequenceEqual(new[] { initialCapture, initialParent }));
+            
+            receivers.Clear();
+            pointer.Capture(null);
+            Assert.True(receivers.SequenceEqual(new object[] { newCapture, newParent, el, root }));
+        }
+    }
+}

+ 1 - 1
tests/Avalonia.UnitTests/MouseTestHelper.cs

@@ -84,9 +84,9 @@ namespace Avalonia.UnitTests
             );
             );
             if (ButtonCount(props) == 0)
             if (ButtonCount(props) == 0)
             {
             {
-                _pointer.Capture(null);
                 target.RaiseEvent(new PointerReleasedEventArgs(source, _pointer, (IVisual)target, position,
                 target.RaiseEvent(new PointerReleasedEventArgs(source, _pointer, (IVisual)target, position,
                     Timestamp(), props, GetModifiers(modifiers), _pressedButton));
                     Timestamp(), props, GetModifiers(modifiers), _pressedButton));
+                _pointer.Capture(null);
             }
             }
             else
             else
                 Move(target, source, position);
                 Move(target, source, position);