From dd285eebde1094e89368cc53f57aea11b0a540df Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 19 Sep 2022 09:48:09 +0200 Subject: [PATCH] More failing tests for two-way bindings. --- .../AvaloniaObjectTests_Binding.cs | 56 ++++++++++++++++++- .../Styling/SetterTests.cs | 54 ++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs index 6ecd1d6cfc..5d3d793bb3 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs @@ -1103,8 +1103,45 @@ namespace Avalonia.Base.UnitTests target.Bind(TextBlock.TextProperty, new Binding("[0]", BindingMode.TwoWay)); } + [Theory] + [InlineData(BindingPriority.LocalValue)] + [InlineData(BindingPriority.StyleTrigger)] + [InlineData(BindingPriority.Style)] + public void TwoWay_Binding_Should_Not_Update_Source_When_Higher_Priority_Value_Set(BindingPriority priority) + { + var target = new Class1(); + var source = new TestTwoWayBindingViewModel(); + var binding = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }; + + target.Bind(Class1.DoubleValueProperty, binding, priority); + target.SetValue(Class1.DoubleValueProperty, 123.4, priority - 1); + + // Setter should not be called because the TwoWay binding with LocalValue priority + // should be overridden by the animated value and the binding made inactive. + Assert.False(source.SetterCalled); + } + + [Theory] + [InlineData(BindingPriority.LocalValue)] + [InlineData(BindingPriority.StyleTrigger)] + [InlineData(BindingPriority.Style)] + public void TwoWay_Binding_Should_Not_Update_Source_When_Higher_Priority_Binding_Added(BindingPriority priority) + { + var target = new Class1(); + var source = new TestTwoWayBindingViewModel(); + var binding1 = new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }; + var binding2 = new BehaviorSubject(123.4); + + target.Bind(Class1.DoubleValueProperty, binding1, priority); + target.Bind(Class1.DoubleValueProperty, binding2, priority - 1); + + // Setter should not be called because the TwoWay binding with LocalValue priority + // should be overridden by the animated binding and the binding made inactive. + Assert.False(source.SetterCalled); + } + [Fact] - public void TwoWay_LocalValue_Binding_Should_Not_Update_Source_When_Animated_Value_Set() + public void TwoWay_Style_Binding_Should_Not_Update_Source_When_StyleTrigger_Value_Set() { var target = new Class1(); var source = new TestTwoWayBindingViewModel(); @@ -1112,11 +1149,26 @@ namespace Avalonia.Base.UnitTests target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source }); target.SetValue(Class1.DoubleValueProperty, 123.4, BindingPriority.Animation); - // Setter should not be called because the TwoWay binding with LocalValue priority + // Setter should not be called because the TwoWay binding with Style priority // should be overridden by the animated value and the binding made inactive. Assert.False(source.SetterCalled); } + [Fact] + public void TwoWay_Style_Binding_Should_Not_Update_Source_When_Animated_Binding_Added() + { + var target = new Class1(); + var source1 = new TestTwoWayBindingViewModel(); + var source2 = new BehaviorSubject(123.4); + + target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source1.Value), BindingMode.TwoWay) { Source = source1 }); + target.Bind(Class1.DoubleValueProperty, source2, BindingPriority.Animation); + + // Setter should not be called because the TwoWay binding with Style priority + // should be overridden by the animated binding and the binding made inactive. + Assert.False(source1.SetterCalled); + } + [Fact] public void Disposing_Completed_Binding_Does_Not_Throw() { diff --git a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs index 79d4817dfd..dc31d3d3ec 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs @@ -447,6 +447,60 @@ namespace Avalonia.Base.UnitTests.Styling Assert.Equal(Brushes.Red, data.Bar); } + [Fact] + public void Styled_Property_Setter_With_TwoWay_Binding_Updates_Source_When_Made_Active() + { + var data = new Data { Bar = Brushes.Red }; + var control = new Border + { + Classes = { "foo" }, + DataContext = data, + }; + + var style1 = new Style(x => x.OfType()) + { + Setters = + { + new Setter + { + Property = Border.BackgroundProperty, + Value = new Binding + { + Path = "Bar", + Mode = BindingMode.TwoWay + } + } + }, + }; + + var style2 = new Style(x => x.OfType().Class("foo")) + { + Setters = + { + new Setter + { + Property = Border.BackgroundProperty, + Value = Brushes.Green, + } + }, + }; + + Apply(style1, control); + Apply(style2, control); + + // `style2` is initially active. + Assert.Equal(Brushes.Green, control.Background); + + // Deactivate `style2`. + control.Classes.Remove("foo"); + Assert.Equal(Brushes.Red, control.Background); + + // The two-way binding from `style1` is now active and so should write back to the + // DataContext. + control.Background = Brushes.Blue; + Assert.Equal(Brushes.Blue, data.Bar); + } + private void Apply(Style style, Control control) { style.TryAttach(control, null);