1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Data bindings - Some WIP stuff

This commit is contained in:
SpoinkyNL 2020-09-02 19:12:31 +02:00
parent 2708e190cb
commit 20e6aa1135
2 changed files with 78 additions and 16 deletions

View File

@ -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<DataBindingModifier> _modifiers = new List<DataBindingModifier>();
public DataBinding(BaseLayerProperty layerProperty, PropertyInfo targetProperty)
{
LayerProperty = layerProperty;
TargetProperty = targetProperty;
}
public DataBinding(BaseLayerProperty layerProperty, PropertyInfo targetProperty, DataBindingEntity entity)
{
LayerProperty = layerProperty;
TargetProperty = targetProperty;
Entity = entity;
}
/// <summary>
/// Gets the layer property this data binding targets
/// </summary>
public BaseLayerProperty LayerProperty { get; private set; }
public BaseLayerProperty LayerProperty { get; }
/// <summary>
/// Gets the inner property this data binding targets
/// </summary>
public PropertyInfo TargetProperty { get; private set; }
public PropertyInfo TargetProperty { get; }
/// <summary>
/// Gets the currently used instance of the data model that contains the source of the data binding
@ -39,8 +54,13 @@ namespace Artemis.Core
/// </summary>
public IReadOnlyList<DataBindingModifier> Modifiers => _modifiers.AsReadOnly();
/// <summary>
/// Gets the compiled function that gets the current value of the data binding target
/// </summary>
public Func<DataModel, object> CompiledTargetAccessor { get; private set; }
internal DataBindingEntity Entity { get; }
/// <summary>
/// Adds a modifier to the data binding's <see cref="Modifiers" /> collection
/// </summary>
@ -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);
}
}
/// <summary>
/// Updates the source of the data binding and re-compiles the expression
/// </summary>
/// <param name="dataModel">The data model of the source</param>
/// <param name="path">The path pointing to the source inside the data model</param>
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();
}
/// <summary>
/// Gets the current value of the data binding
/// </summary>
@ -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)

View File

@ -13,6 +13,8 @@ namespace Artemis.Core
/// </summary>
public class DataBindingModifier
{
private DataBinding _dataBinding;
/// <summary>
/// Creates a new instance of the <see cref="DataBindingModifier" /> class
/// </summary>
@ -37,7 +39,15 @@ namespace Artemis.Core
/// <summary>
/// Gets the data binding this modifier is applied to
/// </summary>
public DataBinding DataBinding { get; internal set; }
public DataBinding DataBinding
{
get => _dataBinding;
internal set
{
_dataBinding = value;
CreateExpression();
}
}
/// <summary>
/// Gets the type of modifier that is being applied
@ -89,7 +99,7 @@ namespace Artemis.Core
/// <returns>The modified value</returns>
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<Func<object, DataModel, object>>(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<Func<object, object>>(modifierExpression, currentValueParameter);