diff --git a/src/Avalonia.Base/Data/Optional.cs b/src/Avalonia.Base/Data/Optional.cs index 8e044d7896b..9dec399e35b 100644 --- a/src/Avalonia.Base/Data/Optional.cs +++ b/src/Avalonia.Base/Data/Optional.cs @@ -153,4 +153,18 @@ public TResult GetValueOrDefault([AllowNull] TResult defaultValue) /// public static Optional Empty => default; } + + public static class OptionalExtensions + { + /// + /// Casts the type of an using only the C# cast operator. + /// + /// The target type. + /// The binding value. + /// The cast value. + public static Optional Cast(this Optional value) + { + return value.HasValue ? new Optional((T)value.Value) : Optional.Empty; + } + } } diff --git a/src/Avalonia.Base/PropertyStore/BindingEntry.cs b/src/Avalonia.Base/PropertyStore/BindingEntry.cs index 3e17a81dd8e..1b29338f078 100644 --- a/src/Avalonia.Base/PropertyStore/BindingEntry.cs +++ b/src/Avalonia.Base/PropertyStore/BindingEntry.cs @@ -127,8 +127,8 @@ public void RaiseValueChanged( sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( owner, (AvaloniaProperty)property, - oldValue.GetValueOrDefault(), - newValue.GetValueOrDefault(), + oldValue.Cast(), + newValue.Cast(), Priority)); } diff --git a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs index d39fc3bb1e5..dc4a1d88c1c 100644 --- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs @@ -65,8 +65,8 @@ public void RaiseValueChanged( sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( owner, (AvaloniaProperty)property, - oldValue.GetValueOrDefault(), - newValue.GetValueOrDefault(), + oldValue.Cast(), + newValue.Cast(), Priority)); } } diff --git a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs index f49b74f4a81..8fe2ad77941 100644 --- a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs @@ -36,8 +36,8 @@ public void RaiseValueChanged( sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( owner, (AvaloniaProperty)property, - oldValue.GetValueOrDefault(), - newValue.GetValueOrDefault(), + oldValue.Cast(), + newValue.Cast(), BindingPriority.LocalValue)); } } diff --git a/src/Avalonia.Base/PropertyStore/PriorityValue.cs b/src/Avalonia.Base/PropertyStore/PriorityValue.cs index 80496fc045a..556f1a62697 100644 --- a/src/Avalonia.Base/PropertyStore/PriorityValue.cs +++ b/src/Avalonia.Base/PropertyStore/PriorityValue.cs @@ -197,8 +197,8 @@ public void RaiseValueChanged( sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( owner, (AvaloniaProperty)property, - oldValue.GetValueOrDefault(), - newValue.GetValueOrDefault(), + oldValue.Cast(), + newValue.Cast(), Priority)); } diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs index 53ad87421ec..01d5752eadc 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs @@ -5,6 +5,7 @@ using System.Reactive.Linq; using System.Text; using Avalonia.Data; +using Avalonia.Layout; using Xunit; namespace Avalonia.Base.UnitTests @@ -104,6 +105,25 @@ public void SetValue_Change_Should_Be_Raised_After_Batch_Update_2() 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(); + + 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 @@ public void Binding_Change_Should_Be_Raised_After_Batch_Update_2() 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.Horizontal); + var raised = new List(); + + 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 @@ public class TestClass : AvaloniaObject public static readonly StyledProperty BarProperty = AvaloniaProperty.Register(nameof(Bar)); + public static readonly StyledProperty BazProperty = + AvaloniaProperty.Register(nameof(Bar), Orientation.Vertical); + public string Foo { get => GetValue(FooProperty); @@ -590,6 +633,12 @@ public string Bar get => GetValue(BarProperty); set => SetValue(BarProperty, value); } + + public Orientation Baz + { + get => GetValue(BazProperty); + set => SetValue(BazProperty, value); + } } public class TestObservable : ObservableBase>