Browse Source

Apply fix to PriorityValue, which works for StyledProperty bindings where the bindings don't have the same priority.

pull/856/head
Jeremy Koritzinsky 9 years ago
parent
commit
6486ffc77f
  1. 83
      src/Avalonia.Base/PriorityValue.cs
  2. 2
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

83
src/Avalonia.Base/PriorityValue.cs

@ -30,6 +30,7 @@ namespace Avalonia
private readonly SingleOrDictionary<int, PriorityLevel> _levels = new SingleOrDictionary<int, PriorityLevel>();
private object _value;
private readonly Func<object, object> _validate;
private static readonly DelayedSetter<PriorityValue, (object value, int priority)> delayedSetter = new DelayedSetter<PriorityValue, (object, int)>();
/// <summary>
/// Initializes a new instance of the <see cref="PriorityValue"/> class.
@ -234,51 +235,67 @@ namespace Avalonia
/// <param name="priority">The priority level that the value came from.</param>
private void UpdateValue(object value, int priority)
{
var notification = value as BindingNotification;
object castValue;
if (notification != null)
{
value = (notification.HasValue) ? notification.Value : null;
}
if (TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
if (!delayedSetter.IsNotifying(this))
{
var old = _value;
var notification = value as BindingNotification;
object castValue;
if (_validate != null && castValue != AvaloniaProperty.UnsetValue)
if (notification != null)
{
castValue = _validate(castValue);
value = (notification.HasValue) ? notification.Value : null;
}
ValuePriority = priority;
_value = castValue;
if (notification?.HasValue == true)
if (!object.Equals(value, _value) && TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
{
notification.SetValue(castValue);
}
var old = _value;
if (notification == null || notification.HasValue)
{
Owner?.Changed(this, old, _value);
}
if (_validate != null && castValue != AvaloniaProperty.UnsetValue)
{
castValue = _validate(castValue);
}
if (notification != null)
{
Owner?.BindingNotificationReceived(this, notification);
ValuePriority = priority;
_value = castValue;
if (notification?.HasValue == true)
{
notification.SetValue(castValue);
}
if (notification == null || notification.HasValue)
{
using (delayedSetter.MarkNotifying(this))
{
Owner?.Changed(this, old, _value);
}
if (delayedSetter.HasPendingSet(this))
{
var pendingSet = delayedSetter.GetFirstPendingSet(this);
UpdateValue(pendingSet.value, pendingSet.priority);
}
}
if (notification != null)
{
Owner?.BindingNotificationReceived(this, notification);
}
}
else
{
Logger.Error(
LogArea.Binding,
Owner,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
Property.Name,
_valueType,
value,
value?.GetType());
}
}
else
{
Logger.Error(
LogArea.Binding,
Owner,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
Property.Name,
_valueType,
value,
value?.GetType());
delayedSetter.AddPendingSet(this, (value, priority));
}
}
}

2
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@ -428,7 +428,7 @@ namespace Avalonia.Base.UnitTests
//here in real life stack overflow exception is thrown issue #855 and #824
target.DoubleValue = 51.001;
Assert.Equal(2, viewModel.SetterInvokedCount);
Assert.Equal(3, viewModel.SetterInvokedCount);
double expected = 51;

Loading…
Cancel
Save