Skip to content

Commit

Permalink
Fixed issue with LocalValue and bindings.
Browse files Browse the repository at this point in the history
  • Loading branch information
grokys committed Nov 21, 2019
1 parent 44e1bd5 commit d5dc470
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 29 deletions.
12 changes: 5 additions & 7 deletions src/Avalonia.Base/PropertyStore/LocalValueEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ namespace Avalonia.PropertyStore
{
internal class LocalValueEntry<T> : IValue<T>
{
public LocalValueEntry(T value) => Value = value;
public Optional<T> Value { get; set; }
private T _value;

public LocalValueEntry(T value) => _value = value;
public Optional<T> Value => _value;
public BindingPriority ValuePriority => BindingPriority.LocalValue;
Optional<object> IValue.Value => Value.ToObject();

public ConstantValueEntry<T> ToConstantValueEntry(StyledPropertyBase<T> property)
{
return new ConstantValueEntry<T>(property, Value.Value, BindingPriority.LocalValue);
}
public void SetValue(T value) => _value = value;
}
}
56 changes: 40 additions & 16 deletions src/Avalonia.Base/PropertyStore/PriorityValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ public PriorityValue(
}
}

public PriorityValue(
IAvaloniaObject owner,
StyledPropertyBase<T> property,
IValueSink sink,
LocalValueEntry<T> existing)
: this(owner, property, sink)
{
_localValue = existing.Value;
Value = _localValue;
ValuePriority = BindingPriority.LocalValue;
}

public StyledPropertyBase<T> Property { get; }
public Optional<T> Value { get; private set; }
public BindingPriority ValuePriority { get; private set; }
Expand Down Expand Up @@ -77,7 +89,11 @@ void IValueSink.ValueChanged<TValue>(
Optional<TValue> oldValue,
BindingValue<TValue> newValue)
{
_localValue = default;
if (priority == BindingPriority.LocalValue)
{
_localValue = default;
}

UpdateEffectiveValue();
}

Expand Down Expand Up @@ -108,29 +124,37 @@ private void UpdateEffectiveValue()
var reachedLocalValues = false;
var value = default(Optional<T>);

for (var i = _entries.Count - 1; i >= 0; --i)
if (_entries.Count > 0)
{
var entry = _entries[i];

if (!reachedLocalValues && entry.Priority >= BindingPriority.LocalValue)
for (var i = _entries.Count - 1; i >= 0; --i)
{
reachedLocalValues = true;
var entry = _entries[i];

if (_localValue.HasValue)
if (!reachedLocalValues && entry.Priority >= BindingPriority.LocalValue)
{
value = _localValue;
ValuePriority = BindingPriority.LocalValue;
break;
reachedLocalValues = true;

if (_localValue.HasValue)
{
value = _localValue;
ValuePriority = BindingPriority.LocalValue;
break;
}
}
}

if (entry.Value.HasValue)
{
value = entry.Value;
ValuePriority = entry.Priority;
break;
if (entry.Value.HasValue)
{
value = entry.Value;
ValuePriority = entry.Priority;
break;
}
}
}
else if (_localValue.HasValue)
{
value = _localValue;
ValuePriority = BindingPriority.LocalValue;
}

if (value != Value)
{
Expand Down
9 changes: 3 additions & 6 deletions src/Avalonia.Base/ValueStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,12 @@ private void SetExisting<T>(
if (priority == BindingPriority.LocalValue)
{
var old = l.Value;
l.Value = value;
l.SetValue(value);
_sink.ValueChanged(property, priority, old, value);
}
else
{
var existing = l.ToConstantValueEntry(property);
var priorityValue = new PriorityValue<T>(_owner, property, this, existing);
priorityValue.SetValue(value, priority);
var priorityValue = new PriorityValue<T>(_owner, property, this, l);
_values.SetValue(property, priorityValue);
}
}
Expand Down Expand Up @@ -205,8 +203,7 @@ private IDisposable BindExisting<T>(
}
else if (slot is LocalValueEntry<T> l)
{
var existing = l.ToConstantValueEntry(property);
priorityValue = new PriorityValue<T>(_owner, property, this, existing);
priorityValue = new PriorityValue<T>(_owner, property, this, l);
}
else
{
Expand Down
31 changes: 31 additions & 0 deletions tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,37 @@ public void Completing_LocalValue_Binding_Reverts_To_Default_Value_Even_When_Loc
Assert.Equal("foodefault", target.GetValue(property));
}

[Fact]
public void Completing_LocalValue_Binding_Should_Not_Revert_To_Set_LocalValue()
{
var target = new Class1();
var source = new BehaviorSubject<string>("bar");

target.SetValue(Class1.FooProperty, "foo");
var sub = target.Bind(Class1.FooProperty, source);

Assert.Equal("bar", target.GetValue(Class1.FooProperty));

sub.Dispose();

Assert.Equal("foodefault", target.GetValue(Class1.FooProperty));
}

[Fact]
public void Completing_Animation_Binding_Reverts_To_Set_LocalValue()
{
var target = new Class1();
var source = new Subject<string>();
var property = Class1.FooProperty;

target.SetValue(property, "foo");
target.Bind(property, source, BindingPriority.Animation);
source.OnNext("bar");
source.OnCompleted();

Assert.Equal("foo", target.GetValue(property));
}

[Fact]
public void Setting_Style_Value_Overrides_Binding_Permanently()
{
Expand Down

0 comments on commit d5dc470

Please sign in to comment.