diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index 47b5a76c8..3bb2066b4 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using Artemis.Core.DataModelExpansions; +using Artemis.Core.Services; +using Artemis.Storage.Entities.Profile.DataBindings; namespace Artemis.Core { @@ -14,15 +16,28 @@ namespace Artemis.Core { private readonly List _modifiers = new List(); + public DataBinding(BaseLayerProperty layerProperty, PropertyInfo targetProperty) + { + LayerProperty = layerProperty; + TargetProperty = targetProperty; + } + + public DataBinding(BaseLayerProperty layerProperty, PropertyInfo targetProperty, DataBindingEntity entity) + { + LayerProperty = layerProperty; + TargetProperty = targetProperty; + Entity = entity; + } + /// /// Gets the layer property this data binding targets /// - public BaseLayerProperty LayerProperty { get; private set; } + public BaseLayerProperty LayerProperty { get; } /// /// Gets the inner property this data binding targets /// - public PropertyInfo TargetProperty { get; private set; } + public PropertyInfo TargetProperty { get; } /// /// Gets the currently used instance of the data model that contains the source of the data binding @@ -39,8 +54,13 @@ namespace Artemis.Core /// public IReadOnlyList Modifiers => _modifiers.AsReadOnly(); + /// + /// Gets the compiled function that gets the current value of the data binding target + /// public Func CompiledTargetAccessor { get; private set; } + internal DataBindingEntity Entity { get; } + /// /// Adds a modifier to the data binding's collection /// @@ -49,7 +69,6 @@ namespace Artemis.Core if (!_modifiers.Contains(modifier)) { modifier.DataBinding = this; - modifier.CreateExpression(); _modifiers.Add(modifier); } } @@ -62,11 +81,33 @@ namespace Artemis.Core if (_modifiers.Contains(modifier)) { modifier.DataBinding = null; - modifier.CreateExpression(); _modifiers.Remove(modifier); } } + /// + /// Updates the source of the data binding and re-compiles the expression + /// + /// The data model of the source + /// The path pointing to the source inside the data model + public void UpdateSource(DataModel dataModel, string path) + { + if (dataModel != null && path == null) + throw new ArtemisCoreException("If a data model is provided, a path is also required"); + if (dataModel == null && path != null) + throw new ArtemisCoreException("If path is provided, a data model is also required"); + + if (dataModel != null) + { + if (!dataModel.ContainsPath(path)) + throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'"); + } + + SourceDataModel = dataModel; + SourcePropertyPath = path; + CreateExpression(); + } + /// /// Gets the current value of the data binding /// @@ -90,7 +131,18 @@ namespace Artemis.Core return dataBindingValue; } - public void Update() + internal void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService) + { + // Source + + // Modifiers + + + foreach (var dataBindingModifier in Modifiers) + dataBindingModifier.Initialize(dataModelService, dataBindingService); + } + + private void CreateExpression() { var listType = SourceDataModel.GetListTypeInPath(SourcePropertyPath); if (listType != null) diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs index 58e241581..4603bd9a6 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs @@ -13,6 +13,8 @@ namespace Artemis.Core /// public class DataBindingModifier { + private DataBinding _dataBinding; + /// /// Creates a new instance of the class /// @@ -37,7 +39,15 @@ namespace Artemis.Core /// /// Gets the data binding this modifier is applied to /// - public DataBinding DataBinding { get; internal set; } + public DataBinding DataBinding + { + get => _dataBinding; + internal set + { + _dataBinding = value; + CreateExpression(); + } + } /// /// Gets the type of modifier that is being applied @@ -89,7 +99,7 @@ namespace Artemis.Core /// The modified value public object Apply(object currentValue) { - var targetType = DataBinding.LayerProperty.GetPropertyType(); + var targetType = DataBinding.TargetProperty.GetType(); if (currentValue.GetType() != targetType) { throw new ArtemisCoreException("The current value of the data binding does not match the type of the target property." + @@ -118,7 +128,7 @@ namespace Artemis.Core return; } - var targetType = DataBinding.LayerProperty.GetPropertyType(); + var targetType = DataBinding.TargetProperty.GetType(); if (!modifierType.SupportsType(targetType)) { throw new ArtemisCoreException($"Cannot apply modifier type {modifierType.GetType().Name} to this modifier because " + @@ -164,7 +174,7 @@ namespace Artemis.Core ParameterDataModel = null; ParameterPropertyPath = null; - var targetType = DataBinding.LayerProperty.GetPropertyType(); + var targetType = DataBinding.TargetProperty.GetType(); // If not null ensure the types match and if not, convert it if (staticValue != null && staticValue.GetType() == targetType) @@ -200,7 +210,7 @@ namespace Artemis.Core else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null) { // Use the target type so JSON.NET has a better idea what to do - var targetType = DataBinding.LayerProperty.GetPropertyType(); + var targetType = DataBinding.TargetProperty.GetType(); object staticValue; try @@ -221,7 +231,7 @@ namespace Artemis.Core } - internal void CreateExpression() + private void CreateExpression() { CompiledDynamicPredicate = null; CompiledStaticPredicate = null; @@ -240,15 +250,15 @@ namespace Artemis.Core if (ParameterDataModel == null) return; - var currentValueParameter = Expression.Parameter(DataBinding.LayerProperty.GetPropertyType()); + var currentValueParameter = Expression.Parameter(DataBinding.TargetProperty.GetType()); // If the right side value is null, the constant type cannot be inferred and must be provided based on the data binding target var rightSideAccessor = CreateAccessor(ParameterDataModel, ParameterPropertyPath, "right", out var rightSideParameter); // A conversion may be required if the types differ // This can cause issues if the DisplayConditionOperator wasn't accurate in it's supported types but that is not a concern here - if (rightSideAccessor.Type != DataBinding.LayerProperty.GetPropertyType()) - rightSideAccessor = Expression.Convert(rightSideAccessor, DataBinding.LayerProperty.GetPropertyType()); + if (rightSideAccessor.Type != DataBinding.TargetProperty.GetType()) + rightSideAccessor = Expression.Convert(rightSideAccessor, DataBinding.TargetProperty.GetType()); var modifierExpression = ModifierType.CreateExpression(currentValueParameter, rightSideAccessor); var lambda = Expression.Lambda>(modifierExpression, currentValueParameter, rightSideParameter); @@ -257,12 +267,12 @@ namespace Artemis.Core private void CreateStaticExpression() { - var currentValueParameter = Expression.Parameter(DataBinding.LayerProperty.GetPropertyType()); + var currentValueParameter = Expression.Parameter(DataBinding.TargetProperty.GetType()); // If the right side value is null, the constant type cannot be inferred and must be provided based on the data binding target var rightSideConstant = ParameterStaticValue != null ? Expression.Constant(ParameterStaticValue) - : Expression.Constant(null, DataBinding.LayerProperty.GetPropertyType()); + : Expression.Constant(null, DataBinding.TargetProperty.GetType()); var modifierExpression = ModifierType.CreateExpression(currentValueParameter, rightSideConstant); var lambda = Expression.Lambda>(modifierExpression, currentValueParameter);