Browse Source

Allow for setting up deferred setter notify handlers without extra allocations.

pull/2933/head
Dariusz Komosiński 7 years ago
parent
commit
11298df527
  1. 14
      src/Avalonia.Base/PriorityValue.cs
  2. 30
      src/Avalonia.Base/Utilities/DeferredSetter.cs

14
src/Avalonia.Base/PriorityValue.cs

@ -24,13 +24,11 @@ namespace Avalonia
/// <see cref="IPriorityValueOwner.Changed"/> method on the /// <see cref="IPriorityValueOwner.Changed"/> method on the
/// owner object is fired with the old and new values. /// owner object is fired with the old and new values.
/// </remarks> /// </remarks>
internal class PriorityValue internal sealed class PriorityValue : ISetAndNotifyHandler<(object,int)>
{ {
private readonly Type _valueType; private readonly Type _valueType;
private readonly SingleOrDictionary<int, PriorityLevel> _levels = new SingleOrDictionary<int, PriorityLevel>(); private readonly SingleOrDictionary<int, PriorityLevel> _levels = new SingleOrDictionary<int, PriorityLevel>();
private readonly Func<object, object> _validate; private readonly Func<object, object> _validate;
private readonly SetAndNotifyCallback<(object, int)> _setAndNotifyCallback;
private (object value, int priority) _value; private (object value, int priority) _value;
private DeferredSetter<object> _setter; private DeferredSetter<object> _setter;
@ -52,7 +50,6 @@ namespace Avalonia
_valueType = valueType; _valueType = valueType;
_value = (AvaloniaProperty.UnsetValue, int.MaxValue); _value = (AvaloniaProperty.UnsetValue, int.MaxValue);
_validate = validate; _validate = validate;
_setAndNotifyCallback = SetAndNotify;
} }
/// <summary> /// <summary>
@ -257,10 +254,15 @@ namespace Avalonia
_setter = Owner.GetNonDirectDeferredSetter(Property); _setter = Owner.GetNonDirectDeferredSetter(Property);
} }
_setter.SetAndNotifyCallback(Property, _setAndNotifyCallback, ref _value, newValue); _setter.SetAndNotifyCallback(Property, this, ref _value, newValue);
}
void ISetAndNotifyHandler<(object, int)>.HandleSetAndNotify(AvaloniaProperty property, ref (object, int) backing, (object, int) value)
{
SetAndNotify(ref backing, value);
} }
private void SetAndNotify(AvaloniaProperty property, ref (object value, int priority) backing, (object value, int priority) update) private void SetAndNotify(ref (object value, int priority) backing, (object value, int priority) update)
{ {
var val = update.value; var val = update.value;
var notification = val as BindingNotification; var notification = val as BindingNotification;

30
src/Avalonia.Base/Utilities/DeferredSetter.cs

@ -5,15 +5,6 @@ using System;
namespace Avalonia.Utilities namespace Avalonia.Utilities
{ {
/// <summary>
/// Callback invoked when deferred setter wants to set a value.
/// </summary>
/// <typeparam name="TValue">Value type.</typeparam>
/// <param name="property">Property being set.</param>
/// <param name="backing">Backing field reference.</param>
/// <param name="value">New value.</param>
internal delegate void SetAndNotifyCallback<TValue>(AvaloniaProperty property, ref TValue backing, TValue value);
/// <summary> /// <summary>
/// A utility class to enable deferring assignment until after property-changed notifications are sent. /// A utility class to enable deferring assignment until after property-changed notifications are sent.
/// Used to fix #855. /// Used to fix #855.
@ -70,14 +61,14 @@ namespace Avalonia.Utilities
return false; return false;
} }
public bool SetAndNotifyCallback<TValue>(AvaloniaProperty property, SetAndNotifyCallback<TValue> setAndNotifyCallback, ref TValue backing, TValue value) public bool SetAndNotifyCallback<TValue>(AvaloniaProperty property, ISetAndNotifyHandler<TValue> setAndNotifyHandler, ref TValue backing, TValue value)
where TValue : TSetRecord where TValue : TSetRecord
{ {
if (!_isNotifying) if (!_isNotifying)
{ {
using (new NotifyDisposable(this)) using (new NotifyDisposable(this))
{ {
setAndNotifyCallback(property, ref backing, value); setAndNotifyHandler.HandleSetAndNotify(property, ref backing, value);
} }
if (!_pendingValues.Empty) if (!_pendingValues.Empty)
@ -86,7 +77,7 @@ namespace Avalonia.Utilities
{ {
while (!_pendingValues.Empty) while (!_pendingValues.Empty)
{ {
setAndNotifyCallback(property, ref backing, (TValue) _pendingValues.Dequeue()); setAndNotifyHandler.HandleSetAndNotify(property, ref backing, (TValue)_pendingValues.Dequeue());
} }
} }
} }
@ -119,4 +110,19 @@ namespace Avalonia.Utilities
} }
} }
} }
/// <summary>
/// Handler for set and notify requests.
/// </summary>
/// <typeparam name="TValue">Value type.</typeparam>
internal interface ISetAndNotifyHandler<TValue>
{
/// <summary>
/// Handles deferred setter requests to set a value.
/// </summary>
/// <param name="property">Property being set.</param>
/// <param name="backing">Backing field reference.</param>
/// <param name="value">New value.</param>
void HandleSetAndNotify(AvaloniaProperty property, ref TValue backing, TValue value);
}
} }

Loading…
Cancel
Save