diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs
index dd6d8425b..f16df9e7d 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs
@@ -15,7 +15,7 @@ namespace Artemis.Core
///
/// Gets the parent of this part
///
- public DataModelConditionPart Parent { get; internal set; }
+ public DataModelConditionPart? Parent { get; internal set; }
///
/// Gets the children of this part
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
index 58fac9e3d..60739c2b5 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
@@ -95,6 +95,7 @@ namespace Artemis.Core
if (!typeof(IList).IsAssignableFrom(listType))
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{newPath}'");
+ ListPath = newPath;
ListType = listType;
IsPrimitiveList = listType.IsPrimitive || listType.IsEnum || listType == typeof(string);
}
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
index ff023d34b..f7e484254 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
@@ -1,6 +1,4 @@
using System;
-using System.Linq;
-using System.Linq.Expressions;
using System.Reflection;
using Artemis.Core.DataModelExpansions;
using Artemis.Storage.Entities.Profile.Abstract;
@@ -41,8 +39,6 @@ namespace Artemis.Core
Initialize();
}
- internal DataModelConditionListPredicateEntity Entity { get; set; }
-
///
/// Gets or sets the predicate type
///
@@ -68,6 +64,8 @@ namespace Artemis.Core
///
public object? RightStaticValue { get; private set; }
+ internal DataModelConditionListPredicateEntity Entity { get; set; }
+
///
/// Updates the left side of the predicate
///
@@ -80,11 +78,12 @@ namespace Artemis.Core
throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}");
LeftPath?.Dispose();
- LeftPath = new DataModelPath(new ListPredicateWrapperDataModel(), path);
+ LeftPath = DataModelConditionList.ListType != null
+ ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path)
+ : null;
ValidateOperator();
ValidateRightSide();
- CreateExpression();
}
///
@@ -99,9 +98,9 @@ namespace Artemis.Core
PredicateType = ListRightSideType.DynamicList;
RightPath?.Dispose();
- RightPath = new DataModelPath(new ListPredicateWrapperDataModel(), path);
-
- CreateExpression();
+ RightPath = DataModelConditionList.ListType != null
+ ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path)
+ : null;
}
///
@@ -118,37 +117,32 @@ namespace Artemis.Core
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}'");
- }
PredicateType = ListRightSideType.Dynamic;
RightPath?.Dispose();
RightPath = new DataModelPath(dataModel, path);
-
- CreateExpression();
}
///
/// Updates the right side of the predicate, makes the predicate static and re-compiles the expression
///
/// The right side value to use
- public void UpdateRightSideStatic(object staticValue)
+ public void UpdateRightSideStatic(object? staticValue)
{
PredicateType = ListRightSideType.Static;
RightPath?.Dispose();
RightPath = null;
SetStaticValue(staticValue);
- CreateExpression();
}
///
/// Updates the operator of the predicate and re-compiles the expression
///
///
- public void UpdateOperator(ConditionOperator conditionOperator)
+ public void UpdateOperator(ConditionOperator? conditionOperator)
{
if (conditionOperator == null)
{
@@ -170,8 +164,6 @@ namespace Artemis.Core
if (conditionOperator.SupportsType(leftType))
Operator = conditionOperator;
-
- CreateExpression();
}
///
@@ -205,6 +197,22 @@ namespace Artemis.Core
return true;
}
+ #region IDisposable
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
+ ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
+
+ LeftPath?.Dispose();
+ RightPath?.Dispose();
+
+ base.Dispose(disposing);
+ }
+
+ #endregion
+
internal override bool EvaluateObject(object target)
{
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
@@ -254,10 +262,12 @@ namespace Artemis.Core
internal override void Save()
{
Entity.PredicateType = (int) PredicateType;
- Entity.LeftPropertyPath = LeftPropertyPath;
- Entity.RightDataModelGuid = RightDataModel?.PluginInfo?.Guid;
- Entity.RightPropertyPath = RightPropertyPath;
+ LeftPath?.Save();
+ Entity.LeftPath = LeftPath?.Entity;
+ RightPath?.Save();
+ Entity.RightPath = RightPath?.Entity;
+
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
if (Operator != null)
@@ -274,19 +284,12 @@ namespace Artemis.Core
private void ApplyParentList()
{
- DataModelConditionPart current = Parent;
-
+ DataModelConditionPart? current = Parent;
while (current != null)
{
if (current is DataModelConditionList parentList)
{
DataModelConditionList = parentList;
-
- if (LeftPropertyPath != null && !ListContainsInnerPath(LeftPropertyPath))
- LeftPropertyPath = null;
- if (RightPropertyPath != null && !ListContainsInnerPath(RightPropertyPath))
- RightPropertyPath = null;
-
return;
}
@@ -299,46 +302,44 @@ namespace Artemis.Core
private void Initialize()
{
- DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded;
- DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved;
ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded;
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
// Left side
- if (Entity.LeftPropertyPath != null && ListContainsInnerPath(Entity.LeftPropertyPath))
- UpdateLeftSide(Entity.LeftPropertyPath);
+ if (Entity.LeftPath != null)
+ {
+ LeftPath = DataModelConditionList.ListType != null
+ ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.LeftPath)
+ : null;
+ }
// Operator
if (Entity.OperatorPluginGuid != null)
{
- ConditionOperator conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
+ ConditionOperator? conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
if (conditionOperator != null)
UpdateOperator(conditionOperator);
}
// Right side dynamic
- if (PredicateType == ListRightSideType.Dynamic && Entity.RightDataModelGuid != null && Entity.RightPropertyPath != null)
- {
- DataModel dataModel = DataModelStore.Get(Entity.RightDataModelGuid.Value)?.DataModel;
- if (dataModel != null && dataModel.ContainsPath(Entity.RightPropertyPath))
- UpdateRightSideDynamic(dataModel, Entity.RightPropertyPath);
- }
+ if (PredicateType == ListRightSideType.Dynamic && Entity.RightPath != null)
+ RightPath = new DataModelPath(null, Entity.RightPath);
// Right side dynamic inside the list
- else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPropertyPath != null)
+ else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPath != null)
{
- if (ListContainsInnerPath(Entity.RightPropertyPath))
- UpdateRightSideDynamic(Entity.RightPropertyPath);
+ RightPath = DataModelConditionList.ListType != null
+ ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
+ : null;
}
// Right side static
else if (PredicateType == ListRightSideType.Static && Entity.RightStaticValue != null)
- {
try
{
- if (LeftPropertyPath != null)
+ if (LeftPath != null && LeftPath.IsValid)
{
// Use the left side type so JSON.NET has a better idea what to do
- Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
- object rightSideValue;
+ Type leftSideType = LeftPath.GetPropertyType()!;
+ object? rightSideValue;
try
{
@@ -363,73 +364,62 @@ namespace Artemis.Core
{
DeserializationLogger.LogListPredicateDeserializationFailure(this, e);
}
- }
- }
-
- private void CreateExpression()
- {
- if (Operator == null)
- return;
-
- // If the operator does not support a right side, create a static expression because the right side will simply be null
- if (PredicateType == ListRightSideType.DynamicList && Operator.SupportsRightSide)
- CreateDynamicListAccessors();
- else if (PredicateType == ListRightSideType.Dynamic && Operator.SupportsRightSide)
- CreateDynamicAccessors();
- else
- CreateStaticAccessors();
}
private void ValidateOperator()
{
- if (LeftPropertyPath == null || Operator == null)
+ if (LeftPath == null || !LeftPath.IsValid || Operator == null)
return;
- Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
- if (!Operator.SupportsType(leftSideType))
+ Type leftType = LeftPath.GetPropertyType()!;
+ if (!Operator.SupportsType(leftType))
Operator = null;
}
private void ValidateRightSide()
{
- Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
+ Type? leftType = LeftPath?.GetPropertyType();
if (PredicateType == ListRightSideType.Dynamic)
{
- if (RightDataModel == null)
+ if (RightPath == null || !RightPath.IsValid)
return;
- Type rightSideType = RightDataModel.GetTypeAtPath(RightPropertyPath);
- if (!leftSideType.IsCastableFrom(rightSideType))
+ Type rightSideType = RightPath.GetPropertyType()!;
+ if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamic(null, null);
}
else if (PredicateType == ListRightSideType.DynamicList)
{
- if (RightPropertyPath == null)
+ if (RightPath == null || !RightPath.IsValid)
return;
- Type rightSideType = GetTypeAtInnerPath(RightPropertyPath);
- if (!leftSideType.IsCastableFrom(rightSideType))
+ Type rightSideType = RightPath.GetPropertyType()!;
+ if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamic(null);
}
else
{
- if (RightStaticValue != null && leftSideType.IsCastableFrom(RightStaticValue.GetType()))
+ if (RightStaticValue != null && (leftType == null || leftType.IsCastableFrom(RightStaticValue.GetType())))
UpdateRightSideStatic(RightStaticValue);
else
UpdateRightSideStatic(null);
}
}
- private void SetStaticValue(object staticValue)
+ private void SetStaticValue(object? staticValue)
{
+ RightPath?.Dispose();
+ RightPath = null;
+
// If the left side is empty simply apply the value, any validation will wait
- if (LeftPropertyPath == null)
+ if (LeftPath == null || !LeftPath.IsValid)
{
RightStaticValue = staticValue;
return;
}
- Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
+ // If the left path is valid we can expect a type
+ Type leftSideType = LeftPath.GetPropertyType()!;
// If not null ensure the types match and if not, convert it
if (staticValue != null && staticValue.GetType() == leftSideType)
@@ -448,107 +438,12 @@ namespace Artemis.Core
if (!(path.Target is ListPredicateWrapperDataModel wrapper))
throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target");
- wrapper.Value = target;
+ wrapper.UntypedValue = target;
return path.GetValue();
}
- private void CreateDynamicListAccessors()
- {
- if (LeftPropertyPath == null || RightPropertyPath == null || Operator == null)
- return;
-
- // List accessors share the same parameter because a list always contains one item per entry
- ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
- Expression leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
- Expression rightSideAccessor = CreateListAccessor(RightPropertyPath, leftSideParameter);
-
- // A conversion may be required if the types differ
- // This can cause issues if the DataModelConditionOperator wasn't accurate in it's supported types but that is not a concern here
- if (rightSideAccessor.Type != leftSideAccessor.Type)
- rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
-
- LeftSideAccessor = Expression.Lambda>(leftSideAccessor, leftSideParameter).Compile();
- RightSideAccessor = Expression.Lambda>(rightSideAccessor, leftSideParameter).Compile();
- }
-
- private void CreateDynamicAccessors()
- {
- if (LeftPropertyPath == null || RightPropertyPath == null || RightDataModel == null || Operator == null)
- return;
-
- // List accessors share the same parameter because a list always contains one item per entry
- ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
- Expression leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
- Expression rightSideAccessor = ExpressionUtilities.CreateDataModelAccessor(RightDataModel, RightPropertyPath, "right", out ParameterExpression rightSideParameter);
-
- // A conversion may be required if the types differ
- // This can cause issues if the DataModelConditionOperator wasn't accurate in it's supported types but that is not a concern here
- if (rightSideAccessor.Type != leftSideAccessor.Type)
- rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
-
- LeftSideAccessor = Expression.Lambda>(leftSideAccessor, leftSideParameter).Compile();
- RightSideAccessor = Expression.Lambda>(rightSideAccessor, rightSideParameter).Compile();
- }
-
- private void CreateStaticAccessors()
- {
- if (!DataModelConditionList.IsPrimitiveList && LeftPropertyPath == null || Operator == null)
- return;
-
- // List accessors share the same parameter because a list always contains one item per entry
- ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
- Expression leftSideAccessor = DataModelConditionList.IsPrimitiveList
- ? Expression.Convert(leftSideParameter, DataModelConditionList.ListType)
- : CreateListAccessor(LeftPropertyPath, leftSideParameter);
-
- LeftSideAccessor = Expression.Lambda>(leftSideAccessor, leftSideParameter).Compile();
- RightSideAccessor = null;
- }
-
- private Expression CreateListAccessor(string path, ParameterExpression listParameter)
- {
- // Create an expression that checks every part of the path for null
- // In the same iteration, create the accessor
- Expression source = Expression.Convert(listParameter, DataModelConditionList.ListType);
- return ExpressionUtilities.CreateNullCheckedAccessor(source, path);
- }
-
- #region IDisposable
-
- ///
- protected override void Dispose(bool disposing)
- {
- DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
- DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
- ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
- ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
-
- LeftPath?.Dispose();
- RightPath?.Dispose();
-
- base.Dispose(disposing);
- }
-
- #endregion
-
#region Event handlers
- private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e)
- {
- DataModel dataModel = e.Registration.DataModel;
- if (dataModel.PluginInfo.Guid == Entity.RightDataModelGuid && dataModel.ContainsPath(Entity.RightPropertyPath))
- UpdateRightSideDynamic(dataModel, Entity.RightPropertyPath);
- }
-
- private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
- {
- if (RightDataModel == e.Registration.DataModel)
- {
- RightSideAccessor = null;
- RightDataModel = null;
- }
- }
-
private void ConditionOperatorStoreOnConditionOperatorAdded(object sender, ConditionOperatorStoreEvent e)
{
ConditionOperator conditionOperator = e.Registration.ConditionOperator;
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs
index d5869fdf5..601bea3ff 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs
@@ -240,8 +240,11 @@ namespace Artemis.Core
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
- Entity.OperatorPluginGuid = Operator?.PluginInfo?.Guid;
- Entity.OperatorType = Operator?.GetType().Name;
+ if (Operator != null)
+ {
+ Entity.OperatorPluginGuid = Operator.PluginInfo.Guid;
+ Entity.OperatorType = Operator.GetType().Name;
+ }
}
internal void Initialize()
@@ -250,7 +253,8 @@ namespace Artemis.Core
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
// Left side
- if (Entity.LeftPath != null) LeftPath = new DataModelPath(null, Entity.LeftPath);
+ if (Entity.LeftPath != null)
+ LeftPath = new DataModelPath(null, Entity.LeftPath);
// Operator
if (Entity.OperatorPluginGuid != null)
diff --git a/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs
index 404f6d5b0..e134b5dc8 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs
@@ -1,9 +1,24 @@
-using Artemis.Core.DataModelExpansions;
+using System;
+using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
- internal class ListPredicateWrapperDataModel : DataModel
+ internal class ListPredicateWrapperDataModel : ListPredicateWrapperDataModel
{
- public object Value { get; set; }
+ public T Value => (UntypedValue is T typedValue ? typedValue : default)!;
+ }
+
+ public abstract class ListPredicateWrapperDataModel : DataModel
+ {
+ public object? UntypedValue { get; set; }
+
+ public static ListPredicateWrapperDataModel Create(Type type)
+ {
+ object? instance = Activator.CreateInstance(typeof(ListPredicateWrapperDataModel<>).MakeGenericType(type));
+ if (instance == null)
+ throw new ArtemisCoreException($"Failed to create an instance of ListPredicateWrapperDataModel for type {type.Name}");
+
+ return (ListPredicateWrapperDataModel) instance;
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Utilities/DeserializationLogger.cs b/src/Artemis.Core/Utilities/DeserializationLogger.cs
index 26caddb4e..e1c176283 100644
--- a/src/Artemis.Core/Utilities/DeserializationLogger.cs
+++ b/src/Artemis.Core/Utilities/DeserializationLogger.cs
@@ -29,9 +29,9 @@ namespace Artemis.Core
_logger.Warning(
exception,
"Failed to deserialize display condition list predicate {list} => {left} {operator} {right}",
- dataModelConditionPredicate.Entity.LeftPropertyPath,
+ dataModelConditionPredicate.Entity.LeftPath?.Path,
dataModelConditionPredicate.Entity.OperatorType,
- dataModelConditionPredicate.Entity.RightPropertyPath
+ dataModelConditionPredicate.Entity.RightPath?.Path
);
}
diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
index 025541f30..513a9af43 100644
--- a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
@@ -6,16 +6,15 @@ namespace Artemis.Storage.Entities.Profile.Conditions
public class DataModelConditionListPredicateEntity : DataModelConditionPartEntity
{
public int PredicateType { get; set; }
-
- public string LeftPropertyPath { get; set; }
- public Guid? RightDataModelGuid { get; set; }
- public string RightPropertyPath { get; set; }
+ public DataModelPathEntity LeftPath { get; set; }
+ public DataModelPathEntity RightPath { get; set; }
// Stored as a string to be able to control serialization and deserialization ourselves
public string RightStaticValue { get; set; }
public string OperatorType { get; set; }
public Guid? OperatorPluginGuid { get; set; }
+
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
index 314e37d39..6d6afaa64 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
@@ -1,5 +1,5 @@
using System;
-using Artemis.Core.DataModelExpansions;
+using Artemis.Core;
using Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared
@@ -10,9 +10,9 @@ namespace Artemis.UI.Shared
private int _index;
private Type _listType;
- public DataModelListPropertiesViewModel(DataModel dataModel, object listItem) : base(null, null, null)
+ public DataModelListPropertiesViewModel(object listItem) : base(null, null, null)
{
- DataModel = dataModel;
+ DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType();
DisplayValue = listItem;
}
@@ -44,7 +44,7 @@ namespace Artemis.UI.Shared
return;
ListType = DisplayValue.GetType();
- PopulateProperties(dataModelUIService, DisplayValue);
+ PopulateProperties(dataModelUIService);
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children)
dataModelVisualizationViewModel.Update(dataModelUIService);
}
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs
index 2001cc4d8..db47e9f7a 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs
@@ -1,5 +1,5 @@
using System;
-using Artemis.Core.DataModelExpansions;
+using Artemis.Core;
using Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared
@@ -9,17 +9,17 @@ namespace Artemis.UI.Shared
private int _index;
private Type _listType;
- public DataModelListPropertyViewModel(DataModel dataModel, object listItem, DataModelDisplayViewModel displayViewModel) : base(null, null, null)
+ public DataModelListPropertyViewModel(object listItem, DataModelDisplayViewModel displayViewModel) : base(null, null, null)
{
- DataModel = dataModel;
+ DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType();
DisplayValue = listItem;
DisplayViewModel = displayViewModel;
}
- public DataModelListPropertyViewModel(DataModel dataModel, object listItem) : base(null, null, null)
+ public DataModelListPropertyViewModel(object listItem) : base(null, null, null)
{
- DataModel = dataModel;
+ DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType();
DisplayValue = listItem;
}
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
index 0bd4a2c91..28c483320 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
@@ -11,8 +11,7 @@ namespace Artemis.UI.Shared
{
private string _count;
private IList _list;
- private DataModelVisualizationViewModel _listTypePropertyViewModel;
-
+
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
{
ListChildren = new BindableCollection();
@@ -44,8 +43,6 @@ namespace Artemis.UI.Shared
// Put an empty value into the list type property view model
if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
{
- dataModelListClassViewModel.DisplayValue = Activator.CreateInstance(dataModelListClassViewModel.ListType);
- dataModelListClassViewModel.Update(dataModelUIService);
return dataModelListClassViewModel;
}
@@ -109,13 +106,13 @@ namespace Artemis.UI.Shared
// If a display VM was found, prefer to use that in any case
DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType);
if (typeViewModel != null)
- return new DataModelListPropertyViewModel(DataModel, listItem, typeViewModel);
+ return new DataModelListPropertyViewModel(listItem, typeViewModel);
// For primitives, create a property view model, it may be null that is fine
if (listType.IsPrimitive || listType.IsEnum || listType == typeof(string))
- return new DataModelListPropertyViewModel(DataModel, listItem);
+ return new DataModelListPropertyViewModel(listItem);
// For other value types create a child view model
if (listType.IsClass || listType.IsStruct())
- return new DataModelListPropertiesViewModel(DataModel, listItem);
+ return new DataModelListPropertiesViewModel(listItem);
return null;
}
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs
index adcda365d..6da643ac7 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs
@@ -13,7 +13,7 @@ namespace Artemis.UI.Shared
public override void Update(IDataModelUIService dataModelUIService)
{
// Always populate properties
- PopulateProperties(dataModelUIService, null);
+ PopulateProperties(dataModelUIService);
// Only update children if the parent is expanded
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
index 744982273..67651698f 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
@@ -125,7 +125,7 @@ namespace Artemis.UI.Shared
}
// If the type couldn't be retrieved either way, assume false
- Type type = DataModelPath.GetPropertyType();
+ Type type = DataModelPath?.GetPropertyType();
if (type == null)
{
IsMatchingFilteredTypes = false;
@@ -178,18 +178,12 @@ namespace Artemis.UI.Shared
return 0;
}
- internal void PopulateProperties(IDataModelUIService dataModelUIService, object overrideValue)
+ internal void PopulateProperties(IDataModelUIService dataModelUIService)
{
- if (IsRootViewModel && overrideValue == null)
+ if (IsRootViewModel)
return;
- Type modelType;
- if (overrideValue != null)
- modelType = overrideValue.GetType();
- else if (Parent.IsRootViewModel)
- modelType = DataModel.GetType();
- else
- modelType = DataModelPath.GetPropertyType();
+ Type modelType = Parent.IsRootViewModel ? DataModel.GetType() : DataModelPath.GetPropertyType();
// Add missing static children
foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
@@ -200,17 +194,13 @@ namespace Artemis.UI.Shared
if (propertyInfo.GetCustomAttribute() != null)
continue;
- DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth(), overrideValue);
+ DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
if (child != null)
Children.Add(child);
}
// Remove static children that should be hidden
- ReadOnlyCollection hiddenProperties;
- if (overrideValue != null && overrideValue is DataModel overrideValueDataModel)
- hiddenProperties = overrideValueDataModel.GetHiddenProperties();
- else
- hiddenProperties = DataModel.GetHiddenProperties();
+ ReadOnlyCollection hiddenProperties = DataModel.GetHiddenProperties();
foreach (PropertyInfo hiddenProperty in hiddenProperties)
{
string childPath = AppendToPath(hiddenProperty.Name);
@@ -220,11 +210,7 @@ namespace Artemis.UI.Shared
}
// Add missing dynamic children
- object value;
- if (overrideValue != null)
- value = overrideValue;
- else
- value = Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
+ object value = Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
if (value is DataModel dataModel)
{
foreach (KeyValuePair kvp in dataModel.DynamicDataModels)
@@ -233,7 +219,7 @@ namespace Artemis.UI.Shared
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
continue;
- DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth(), overrideValue);
+ DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
if (child != null)
Children.Add(child);
}
@@ -245,12 +231,12 @@ namespace Artemis.UI.Shared
Children.RemoveRange(toRemoveDynamic);
}
- private DataModelVisualizationViewModel CreateChild(IDataModelUIService dataModelUIService, string path, int depth, object overrideValue)
+ private DataModelVisualizationViewModel CreateChild(IDataModelUIService dataModelUIService, string path, int depth)
{
if (depth > MaxDepth)
return null;
- DataModelPath dataModelPath = new DataModelPath(overrideValue ?? DataModel, path);
+ DataModelPath dataModelPath = new DataModelPath(DataModel, path);
if (!dataModelPath.IsValid)
return null;
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs
index 10e820f58..fe0c16bb0 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs
@@ -79,18 +79,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public DelegateCommand SelectOperatorCommand { get; }
- public void Dispose()
- {
- if (!_isPrimitiveList)
- {
- LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
- LeftSideSelectionViewModel.Dispose();
- }
-
- DisposeRightSideDynamic();
- DisposeRightSideStatic();
- }
-
public override void Delete()
{
base.Delete();
@@ -123,7 +111,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public override void Update()
{
- Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid;
+ Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid;
if (listDataModelGuid == null)
return;
@@ -132,7 +120,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188));
LeftSideSelectionViewModel.SelectedPropertyViewModel = LeftSideSelectionViewModel.DataModelViewModel.GetChildByPath(
- listDataModelGuid.Value, DataModelConditionListPredicate.LeftPropertyPath
+ listDataModelGuid.Value, DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
);
}
@@ -142,14 +130,20 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
// Get the supported operators
Operators.Clear();
- Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType));
+ Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType ?? typeof(object)));
if (DataModelConditionListPredicate.Operator == null)
- DataModelConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType)));
+ DataModelConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType ?? typeof(object))));
SelectedOperator = DataModelConditionListPredicate.Operator;
+ if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
+ {
+ DisposeRightSideStatic();
+ DisposeRightSideDynamic();
+ }
// Ensure the right side has the proper VM
- if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic ||
- DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList)
+ if ((DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic ||
+ DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) &&
+ SelectedOperator.SupportsRightSide)
{
DisposeRightSideStatic();
if (RightSideSelectionViewModel == null)
@@ -164,20 +158,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic)
- {
RightSideSelectionViewModel.PopulateSelectedPropertyViewModel(
- DataModelConditionListPredicate.RightDataModel,
- DataModelConditionListPredicate.RightPropertyPath
+ DataModelConditionListPredicate.RightPath?.Target,
+ DataModelConditionListPredicate.RightPath?.Path
);
- }
else
- {
RightSideSelectionViewModel.SelectedPropertyViewModel = RightSideSelectionViewModel.DataModelViewModel.GetChildByPath(
- listDataModelGuid.Value, DataModelConditionListPredicate.RightPropertyPath
+ listDataModelGuid.Value, DataModelConditionListPredicate.RightPath?.Path
);
- }
}
- else
+ else if (SelectedOperator.SupportsRightSide)
{
DisposeRightSideDynamic();
if (RightSideInputViewModel == null)
@@ -205,16 +195,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void ApplyRightSideDynamic()
{
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic)
- {
DataModelConditionListPredicate.UpdateRightSideDynamic(
RightSideSelectionViewModel.SelectedPropertyViewModel.DataModel,
RightSideSelectionViewModel.SelectedPropertyViewModel.Path
);
- }
else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList)
- {
DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.SelectedPropertyViewModel.Path);
- }
_profileEditorService.UpdateSelectedProfileElement();
Update();
@@ -238,10 +224,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
private DataModelVisualizationViewModel GetListDataModel()
{
- DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true);
- if (DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid == null)
- return null;
+ if (DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid == null)
+ throw new ArtemisUIException("Failed to retrieve the list data model VM for this list predicate because it has no list path");
+ DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true);
DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath(
DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value,
DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
@@ -293,5 +279,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideSelectionViewModel = null;
}
}
+
+ public void Dispose()
+ {
+ if (!_isPrimitiveList)
+ {
+ LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
+ LeftSideSelectionViewModel.Dispose();
+ }
+
+ DisposeRightSideDynamic();
+ DisposeRightSideStatic();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
index d0288eb10..36144400a 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
@@ -107,7 +107,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public override void Update()
{
- TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath.Target, DataModelConditionList.ListPath.Path);
+ TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath?.Target, DataModelConditionList.ListPath?.Path);
NotifyOfPropertyChange(nameof(SelectedListOperator));
// Remove VMs of effects no longer applied on the layer
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
index 64808dd19..52055076b 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
@@ -118,25 +118,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel(
- DataModelConditionPredicate.LeftPath.Target as DataModel,
- DataModelConditionPredicate.LeftPath.Path
+ DataModelConditionPredicate.LeftPath?.Target,
+ DataModelConditionPredicate.LeftPath?.Path
);
Type leftSideType = LeftSideSelectionViewModel.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType();
// Get the supported operators
Operators.Clear();
- Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType));
+ Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType ?? typeof(object)));
if (DataModelConditionPredicate.Operator == null)
- DataModelConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType)));
+ DataModelConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType ?? typeof(object))));
SelectedOperator = DataModelConditionPredicate.Operator;
- if (!SelectedOperator.SupportsRightSide)
+ if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
{
DisposeRightSideStatic();
DisposeRightSideDynamic();
}
// Ensure the right side has the proper VM
- Type targetType = LeftSideSelectionViewModel?.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType();
if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide)
{
DisposeRightSideStatic();
@@ -148,24 +147,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
}
RightSideSelectionViewModel.PopulateSelectedPropertyViewModel(
- DataModelConditionPredicate.RightPath.Target as DataModel,
- DataModelConditionPredicate.RightPath.Path
+ DataModelConditionPredicate.RightPath?.Target,
+ DataModelConditionPredicate.RightPath?.Path
);
- RightSideSelectionViewModel.FilterTypes = new[] {targetType};
+ RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
}
else if (SelectedOperator.SupportsRightSide)
{
DisposeRightSideDynamic();
if (RightSideInputViewModel == null)
{
- RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(targetType);
+ RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType);
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
}
RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue;
- if (RightSideInputViewModel.TargetType != targetType)
- RightSideInputViewModel.UpdateTargetType(targetType);
+ if (RightSideInputViewModel.TargetType != leftSideType)
+ RightSideInputViewModel.UpdateTargetType(leftSideType);
}
}
@@ -213,7 +212,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
ApplyLeftSide();
}
- private void RightSideOnPropertySelected(object? sender, DataModelInputDynamicEventArgs e)
+ private void RightSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
{
ApplyRightSideDynamic();
}
diff --git a/src/Artemis.sln.DotSettings b/src/Artemis.sln.DotSettings
index 382c2aef7..6f469af9c 100644
--- a/src/Artemis.sln.DotSettings
+++ b/src/Artemis.sln.DotSettings
@@ -207,6 +207,7 @@
ERROR
ERROR
ERROR
+ UI
True
True
True