Browse Source

Merge branch 'master' into fixes/TextBlockHorizontalAlignment

Dan Walmsley 4 years ago
parent
commit
4118cbe344

+ 14 - 0
src/Avalonia.Base/Data/Optional.cs

@@ -153,4 +153,18 @@ namespace Avalonia.Data
         /// </summary>
         public static Optional<T> Empty => default;
     }
+
+    public static class OptionalExtensions
+    {
+        /// <summary>
+        /// Casts the type of an <see cref="Optional{T}"/> using only the C# cast operator.
+        /// </summary>
+        /// <typeparam name="T">The target type.</typeparam>
+        /// <param name="value">The binding value.</param>
+        /// <returns>The cast value.</returns>
+        public static Optional<T> Cast<T>(this Optional<object> value)
+        {
+            return value.HasValue ? new Optional<T>((T)value.Value) : Optional<T>.Empty;
+        }
+    }
 }

+ 2 - 2
src/Avalonia.Base/PropertyStore/BindingEntry.cs

@@ -127,8 +127,8 @@ namespace Avalonia.PropertyStore
             sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
                 owner,
                 (AvaloniaProperty<T>)property,
-                oldValue.GetValueOrDefault<T>(),
-                newValue.GetValueOrDefault<T>(),
+                oldValue.Cast<T>(),
+                newValue.Cast<T>(),
                 Priority));
         }
 

+ 2 - 2
src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs

@@ -65,8 +65,8 @@ namespace Avalonia.PropertyStore
             sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
                 owner,
                 (AvaloniaProperty<T>)property,
-                oldValue.GetValueOrDefault<T>(),
-                newValue.GetValueOrDefault<T>(),
+                oldValue.Cast<T>(),
+                newValue.Cast<T>(),
                 Priority));
         }
     }

+ 2 - 2
src/Avalonia.Base/PropertyStore/LocalValueEntry.cs

@@ -36,8 +36,8 @@ namespace Avalonia.PropertyStore
             sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
                 owner,
                 (AvaloniaProperty<T>)property,
-                oldValue.GetValueOrDefault<T>(),
-                newValue.GetValueOrDefault<T>(),
+                oldValue.Cast<T>(),
+                newValue.Cast<T>(),
                 BindingPriority.LocalValue));
         }
     }

+ 2 - 2
src/Avalonia.Base/PropertyStore/PriorityValue.cs

@@ -197,8 +197,8 @@ namespace Avalonia.PropertyStore
             sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
                 owner,
                 (AvaloniaProperty<T>)property,
-                oldValue.GetValueOrDefault<T>(),
-                newValue.GetValueOrDefault<T>(),
+                oldValue.Cast<T>(),
+                newValue.Cast<T>(),
                 Priority));
         }
 

+ 49 - 0
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs

@@ -5,6 +5,7 @@ using System.Reactive.Disposables;
 using System.Reactive.Linq;
 using System.Text;
 using Avalonia.Data;
+using Avalonia.Layout;
 using Xunit;
 
 namespace Avalonia.Base.UnitTests
@@ -104,6 +105,25 @@ namespace Avalonia.Base.UnitTests
             Assert.Equal("baz", target.Foo);
         }
 
+        [Fact]
+        public void SetValue_Change_Should_Be_Raised_After_Batch_Update_3()
+        {
+            var target = new TestClass();
+            var raised = new List<AvaloniaPropertyChangedEventArgs>();
+
+            target.PropertyChanged += (s, e) => raised.Add(e);
+
+            target.BeginBatchUpdate();
+            target.SetValue(TestClass.BazProperty, Orientation.Horizontal, BindingPriority.LocalValue);
+            target.EndBatchUpdate();
+
+            Assert.Equal(1, raised.Count);
+            Assert.Equal(TestClass.BazProperty, raised[0].Property);
+            Assert.Equal(Orientation.Vertical, raised[0].OldValue);
+            Assert.Equal(Orientation.Horizontal, raised[0].NewValue);
+            Assert.Equal(Orientation.Horizontal, target.Baz);
+        }
+
         [Fact]
         public void SetValue_Changes_Should_Be_Raised_In_Correct_Order_After_Batch_Update()
         {
@@ -234,6 +254,26 @@ namespace Avalonia.Base.UnitTests
             Assert.Equal("baz", raised[0].NewValue);
         }
 
+        [Fact]
+        public void Binding_Change_Should_Be_Raised_After_Batch_Update_3()
+        {
+            var target = new TestClass();
+            var observable = new TestObservable<Orientation>(Orientation.Horizontal);
+            var raised = new List<AvaloniaPropertyChangedEventArgs>();
+
+            target.PropertyChanged += (s, e) => raised.Add(e);
+
+            target.BeginBatchUpdate();
+            target.Bind(TestClass.BazProperty, observable, BindingPriority.LocalValue);
+            target.EndBatchUpdate();
+
+            Assert.Equal(1, raised.Count);
+            Assert.Equal(TestClass.BazProperty, raised[0].Property);
+            Assert.Equal(Orientation.Vertical, raised[0].OldValue);
+            Assert.Equal(Orientation.Horizontal, raised[0].NewValue);
+            Assert.Equal(Orientation.Horizontal, target.Baz);
+        }
+
         [Fact]
         public void Binding_Completion_Should_Be_Raised_After_Batch_Update()
         {
@@ -579,6 +619,9 @@ namespace Avalonia.Base.UnitTests
             public static readonly StyledProperty<string> BarProperty =
                 AvaloniaProperty.Register<TestClass, string>(nameof(Bar));
 
+            public static readonly StyledProperty<Orientation> BazProperty =
+                AvaloniaProperty.Register<TestClass, Orientation>(nameof(Bar), Orientation.Vertical);
+
             public string Foo
             {
                 get => GetValue(FooProperty);
@@ -590,6 +633,12 @@ namespace Avalonia.Base.UnitTests
                 get => GetValue(BarProperty);
                 set => SetValue(BarProperty, value);
             }
+
+            public Orientation Baz
+            {
+                get => GetValue(BazProperty);
+                set => SetValue(BazProperty, value);
+            }
         }
 
         public class TestObservable<T> : ObservableBase<BindingValue<T>>