Browse Source

Make bindings react to PropertyChanged even if property hasn't changed (#16150)

* Added failing test for #16137.

* Raise node change even if value hasn't changed.

Fixes #16137.
release/11.1.0-rc2
Steven Kirk 2 years ago
parent
commit
2ba45511d0
  1. 20
      src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs
  2. 20
      tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.Property.cs
  3. 10
      tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.cs

20
src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs

@ -211,24 +211,8 @@ internal abstract class ExpressionNode
protected void SetValue(object? value, Exception? dataValidationError = null)
{
Debug.Assert(value is not BindingNotification);
if (Owner is null)
return;
// We raise a change notification if:
//
// - This is the initial value (_value is null)
// - There is a data validation error
// - There is no data validation error, but the owner has one
// - The new value is different to the old value
if (_value is null ||
dataValidationError is not null ||
(dataValidationError is null && Owner.ErrorType == BindingErrorType.DataValidationError) ||
!Equals(value, _value))
{
_value = value;
Owner.OnNodeValueChanged(Index, value, dataValidationError);
}
_value = value;
Owner?.OnNodeValueChanged(Index, value, dataValidationError);
}
/// <summary>

20
tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.Property.cs

@ -226,6 +226,26 @@ namespace Avalonia.Base.UnitTests.Data.Core
GC.KeepAlive(data);
}
[Fact]
public void Converter_Should_Be_Called_On_PropertyChanged_Even_If_Property_Not_Changed()
{
// Issue #16137
var data = new ViewModel();
var converter = new PrefixConverter("foo");
var target = CreateTargetWithSource(
data,
o => o.IntValue,
converter: converter,
targetProperty: TargetClass.StringProperty);
Assert.Equal("foo0", target.String);
converter.Prefix = "bar";
data.RaisePropertyChanged(nameof(data.IntValue));
Assert.Equal("bar0", target.String);
}
private class DerivedViewModel : ViewModel
{
}

10
tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.cs

@ -417,14 +417,20 @@ public abstract partial class BindingExpressionTests
protected class PrefixConverter : IValueConverter
{
public PrefixConverter(string? prefix = null) => Prefix = prefix;
public string? Prefix { get; set; }
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (targetType != typeof(string))
return value;
var result = value?.ToString() ?? string.Empty;
if (parameter is not null)
result = parameter.ToString() + result;
var prefix = parameter?.ToString() ?? Prefix;
if (prefix is not null)
result = prefix + result;
return result;
}

Loading…
Cancel
Save