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

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 //here in real life stack overflow exception is thrown issue #855 and #824
target.DoubleValue = 51.001; target.DoubleValue = 51.001;
Assert.Equal(2, viewModel.SetterInvokedCount); Assert.Equal(3, viewModel.SetterInvokedCount);
double expected = 51; double expected = 51;

Loading…
Cancel
Save