using System;
using System.Linq;
using System.Linq.Expressions;
namespace Artemis.Core
{
///
/// Represents a data binding converter that acts as the bridge between a
/// and a
///
public abstract class DataBindingConverter : IDataBindingConverter
{
///
/// A dynamically compiled getter pointing to the data bound property
///
public Func ValueGetter { get; private set; }
///
/// A dynamically compiled setter pointing to the data bound property
///
public Action ValueSetter { get; private set; }
///
/// Gets the data binding this converter is applied to
///
public DataBinding DataBinding { get; private set; }
///
/// Gets whether or not this data binding converter supports the method
///
public bool SupportsSum { get; protected set; }
///
/// Gets whether or not this data binding converter supports the method
///
public bool SupportsInterpolate { get; protected set; }
///
public Type SupportedType => typeof(TProperty);
///
/// Returns the sum of and
///
public abstract TProperty Sum(TProperty a, TProperty b);
///
/// Returns the the interpolated value between and on a scale (generally)
/// between 0.0 and 1.0 defined by the
/// Note: The progress may go be negative or go beyond 1.0 depending on the easing method used
///
/// The value to interpolate away from
/// The value to interpolate towards
/// The progress of the interpolation between 0.0 and 1.0
///
public abstract TProperty Interpolate(TProperty a, TProperty b, double progress);
///
/// Applies the to the layer property
///
///
public abstract void ApplyValue(TProperty value);
///
/// Returns the current base value of the data binding
///
public abstract TProperty GetValue();
///
/// Called when the data binding converter has been initialized and the is available
///
protected virtual void OnInitialized()
{
}
internal void Initialize(DataBinding dataBinding)
{
DataBinding = dataBinding;
ValueGetter = CreateValueGetter();
ValueSetter = CreateValueSetter();
OnInitialized();
}
private Func CreateValueGetter()
{
if (DataBinding.TargetProperty?.DeclaringType == null)
return null;
var getterMethod = DataBinding.TargetProperty.GetGetMethod();
if (getterMethod == null)
return null;
var constant = Expression.Constant(DataBinding.LayerProperty);
// The path is null if the registration is applied to the root (LayerProperty.CurrentValue)
var property = DataBinding.Registration.Path == null
? Expression.Property(constant, DataBinding.TargetProperty)
: (MemberExpression) DataBinding.Registration.Path.Split('.').Aggregate(constant, Expression.Property);
var lambda = Expression.Lambda>(property);
return lambda.Compile();
}
private Action CreateValueSetter()
{
if (DataBinding.TargetProperty?.DeclaringType == null)
return null;
var setterMethod = DataBinding.TargetProperty.GetSetMethod();
if (setterMethod == null)
return null;
var constant = Expression.Constant(DataBinding.LayerProperty);
var propertyValue = Expression.Parameter(typeof(TProperty), "propertyValue");
var body = Expression.Call(constant, setterMethod, propertyValue);
var lambda = Expression.Lambda>(body, propertyValue);
return lambda.Compile();
}
}
}