Browse Source

Fix OneWayToSource bindings with read-only properties. (#14513)

* Added more OneWayToSource tests.

One of whom is failing.

* Don't public value for OneWayToSource bindings.

Looks to have been a brainfart. This allows `OneWayToSource` bindings to read-only properties.
pull/14530/head
Steven Kirk 2 years ago
committed by GitHub
parent
commit
f6fe68eddb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      src/Avalonia.Base/Data/Core/BindingExpression.cs
  2. 67
      tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.Mode.cs
  3. 14
      tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.cs

3
src/Avalonia.Base/Data/Core/BindingExpression.cs

@ -375,9 +375,6 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri
TryGetTarget(out var target) && TryGetTarget(out var target) &&
TargetProperty is not null) TargetProperty is not null)
{ {
if (_mode is BindingMode.OneWayToSource)
PublishValue(target.GetValue(TargetProperty));
var trigger = UpdateSourceTrigger; var trigger = UpdateSourceTrigger;
if (trigger is UpdateSourceTrigger.PropertyChanged) if (trigger is UpdateSourceTrigger.PropertyChanged)

67
tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests.Mode.cs

@ -1,5 +1,6 @@
using Avalonia.Data; using Avalonia.Data;
using Xunit; using Xunit;
using Xunit.Sdk;
#nullable enable #nullable enable
@ -67,4 +68,70 @@ public partial class BindingExpressionTests
data2.DoubleValue = 0.2; data2.DoubleValue = 0.2;
Assert.Equal(0.5, target.Double); Assert.Equal(0.5, target.Double);
} }
[Fact]
public void OneWayToSource_Binding_Updates_Source_When_Target_Changes()
{
var data = new ViewModel();
var target = CreateTarget<ViewModel, string?>(
x => x.StringValue,
dataContext: data,
mode: BindingMode.OneWayToSource);
Assert.Null(data.StringValue);
target.String = "foo";
Assert.Equal("foo", data.StringValue);
}
[Fact]
public void OneWayToSource_Binding_Does_Not_Update_Target_When_Source_Changes()
{
var data = new ViewModel();
var target = CreateTarget<ViewModel, string?>(
x => x.StringValue,
dataContext: data,
mode: BindingMode.OneWayToSource);
target.String = "foo";
Assert.Equal("foo", data.StringValue);
data.StringValue = "bar";
Assert.Equal("foo", target.String);
}
[Fact]
public void OneWayToSource_Binding_Updates_Source_When_DataContext_Changes()
{
var data1 = new ViewModel();
var data2 = new ViewModel();
var target = CreateTarget<ViewModel, string?>(
x => x.StringValue,
dataContext: data1,
mode: BindingMode.OneWayToSource);
target.String = "foo";
Assert.Equal("foo", data1.StringValue);
target.DataContext = data2;
Assert.Equal("foo", data2.StringValue);
}
[Fact]
public void Can_Bind_Readonly_Property_OneWayToSource()
{
var data = new ViewModel();
var target = CreateTarget<ViewModel, string?>(
x => x.StringValue,
dataContext: data,
mode: BindingMode.OneWayToSource,
targetProperty: TargetClass.ReadOnlyStringProperty);
Assert.Equal("readonly", data.StringValue);
target.SetReadOnlyString("foo");
Assert.Equal("foo", data.StringValue);
}
} }

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

@ -343,6 +343,12 @@ public abstract partial class BindingExpressionTests
AvaloniaProperty.Register<TargetClass, object?>("Object"); AvaloniaProperty.Register<TargetClass, object?>("Object");
public static readonly StyledProperty<string?> StringProperty = public static readonly StyledProperty<string?> StringProperty =
AvaloniaProperty.Register<TargetClass, string?>("String"); AvaloniaProperty.Register<TargetClass, string?>("String");
public static readonly DirectProperty<TargetClass, string?> ReadOnlyStringProperty =
AvaloniaProperty.RegisterDirect<TargetClass, string?>(
nameof(ReadOnlyString),
o => o.ReadOnlyString);
private string? _readOnlyString = "readonly";
static TargetClass() static TargetClass()
{ {
@ -379,10 +385,18 @@ public abstract partial class BindingExpressionTests
set => SetValue(StringProperty, value); set => SetValue(StringProperty, value);
} }
public string? ReadOnlyString
{
get => _readOnlyString;
private set => SetAndRaise(ReadOnlyStringProperty, ref _readOnlyString, value);
}
public Dictionary<AvaloniaProperty, BindingNotification> BindingNotifications { get; } = new(); public Dictionary<AvaloniaProperty, BindingNotification> BindingNotifications { get; } = new();
public override string ToString() => nameof(TargetClass); public override string ToString() => nameof(TargetClass);
public void SetReadOnlyString(string? value) => ReadOnlyString = value;
protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
{ {
base.UpdateDataValidation(property, state, error); base.UpdateDataValidation(property, state, error);

Loading…
Cancel
Save