From 8959d55418132248e2c74d11b7d2c37d8e0e2b20 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 30 Apr 2021 12:13:12 +0200 Subject: [PATCH] Correctly handle default values in batch update notifications. We were previously calling `Optional.GetValueOrDefault()` in order to convert an `Optional` to an `Optional` which meant that empty values were getting converted to default values, meaning that in certain cases change notifications weren't raised. Add an `Optional.Cast()` methods (like we have in `BindingValue`) and use that in order to preserve empty values when ending a batch update operation. --- src/Avalonia.Base/Data/Optional.cs | 14 ++++++++++++++ src/Avalonia.Base/PropertyStore/BindingEntry.cs | 4 ++-- .../PropertyStore/ConstantValueEntry.cs | 4 ++-- src/Avalonia.Base/PropertyStore/LocalValueEntry.cs | 4 ++-- src/Avalonia.Base/PropertyStore/PriorityValue.cs | 4 ++-- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Base/Data/Optional.cs b/src/Avalonia.Base/Data/Optional.cs index 8e044d7896..9dec399e35 100644 --- a/src/Avalonia.Base/Data/Optional.cs +++ b/src/Avalonia.Base/Data/Optional.cs @@ -153,4 +153,18 @@ namespace Avalonia.Data /// 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 3e17a81dd8..1b29338f07 100644 --- a/src/Avalonia.Base/PropertyStore/BindingEntry.cs +++ b/src/Avalonia.Base/PropertyStore/BindingEntry.cs @@ -127,8 +127,8 @@ namespace Avalonia.PropertyStore 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 d39fc3bb1e..dc4a1d88c1 100644 --- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs @@ -65,8 +65,8 @@ namespace Avalonia.PropertyStore 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 f49b74f4a8..8fe2ad7794 100644 --- a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs @@ -36,8 +36,8 @@ namespace Avalonia.PropertyStore 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 80496fc045..556f1a6269 100644 --- a/src/Avalonia.Base/PropertyStore/PriorityValue.cs +++ b/src/Avalonia.Base/PropertyStore/PriorityValue.cs @@ -197,8 +197,8 @@ namespace Avalonia.PropertyStore sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( owner, (AvaloniaProperty)property, - oldValue.GetValueOrDefault(), - newValue.GetValueOrDefault(), + oldValue.Cast(), + newValue.Cast(), Priority)); }