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.
pull/16159/head
Steven Kirk
2 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with
30 additions and
20 deletions
-
src/Avalonia.Base/Data/Core/ExpressionNodes/ExpressionNode.cs
-
tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.Property.cs
-
tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.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>
|
|
|
|
|
|
|
|
@ -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 |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
@ -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; |
|
|
|
} |
|
|
|
|
|
|
|
|