Skip to content

Commit

Permalink
Merge pull request #5852 from AvaloniaUI/fixes/batch-update-default-v…
Browse files Browse the repository at this point in the history
…alue

Correctly handle default values in batch update notifications.
  • Loading branch information
Dan Walmsley committed Apr 30, 2021
1 parent 4336ec9 commit 60ab70a
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 8 deletions.
14 changes: 14 additions & 0 deletions src/Avalonia.Base/Data/Optional.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,18 @@ public TResult GetValueOrDefault<TResult>([AllowNull] TResult defaultValue)
/// </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;
}
}
}
4 changes: 2 additions & 2 deletions src/Avalonia.Base/PropertyStore/BindingEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ public void Start(bool ignoreBatchUpdate)
sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
owner,
(AvaloniaProperty<T>)property,
oldValue.GetValueOrDefault<T>(),
newValue.GetValueOrDefault<T>(),
oldValue.Cast<T>(),
newValue.Cast<T>(),
Priority));
}

Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public void Dispose()
sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
owner,
(AvaloniaProperty<T>)property,
oldValue.GetValueOrDefault<T>(),
newValue.GetValueOrDefault<T>(),
oldValue.Cast<T>(),
newValue.Cast<T>(),
Priority));
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Base/PropertyStore/LocalValueEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public Optional<T> GetValue(BindingPriority maxPriority)
sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
owner,
(AvaloniaProperty<T>)property,
oldValue.GetValueOrDefault<T>(),
newValue.GetValueOrDefault<T>(),
oldValue.Cast<T>(),
newValue.Cast<T>(),
BindingPriority.LocalValue));
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Base/PropertyStore/PriorityValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ public BindingEntry<T> AddBinding(IObservable<BindingValue<T>> source, BindingPr
sink.ValueChanged(new AvaloniaPropertyChangedEventArgs<T>(
owner,
(AvaloniaProperty<T>)property,
oldValue.GetValueOrDefault<T>(),
newValue.GetValueOrDefault<T>(),
oldValue.Cast<T>(),
newValue.Cast<T>(),
Priority));
}

Expand Down
49 changes: 49 additions & 0 deletions tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_BatchUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Reactive.Linq;
using System.Text;
using Avalonia.Data;
using Avalonia.Layout;
using Xunit;

namespace Avalonia.Base.UnitTests
Expand Down Expand Up @@ -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<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()
{
Expand Down Expand Up @@ -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>(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()
{
Expand Down Expand Up @@ -579,6 +619,9 @@ public class TestClass : AvaloniaObject
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);
Expand All @@ -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<T> : ObservableBase<BindingValue<T>>
Expand Down

0 comments on commit 60ab70a

Please sign in to comment.