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(); } } }