diff --git a/src/Artemis.Core/Extensions/TypeExtensions.cs b/src/Artemis.Core/Extensions/TypeExtensions.cs
index 039087fff..7878bc5a6 100644
--- a/src/Artemis.Core/Extensions/TypeExtensions.cs
+++ b/src/Artemis.Core/Extensions/TypeExtensions.cs
@@ -88,11 +88,33 @@ namespace Artemis.Core
}
///
- /// Returns the default value of the given type
+ /// Returns the default value of the given type
///
public static object GetDefault(this Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
+
+ ///
+ /// Determines whether the given type is a generic enumerable
+ ///
+ public static bool IsGenericEnumerable(this Type type)
+ {
+ return type.GetInterfaces().Any(x =>
+ x.IsGenericType &&
+ x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
+ }
+
+ ///
+ /// Determines the type of the provided generic enumerable type
+ ///
+ public static Type? GetGenericEnumerableType(this Type type)
+ {
+ Type enumerableType = type.GetInterfaces().FirstOrDefault(x =>
+ x.IsGenericType &&
+ x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
+
+ return enumerableType?.GenericTypeArguments[0];
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
index 55da596fa..a3459f385 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs
@@ -93,7 +93,7 @@ namespace Artemis.Core
if (ListPath != null)
{
Type listType = ListPath.GetPropertyType()!;
- ListType = listType.GetGenericArguments()[0];
+ ListType = listType.GetGenericEnumerableType();
IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
// Create a new root group
@@ -129,10 +129,10 @@ namespace Artemis.Core
if (!Children.Any())
return false;
- if (!(target is IList list))
+ if (!(target is IEnumerable enumerable))
return false;
- IEnumerable objectList = list.Cast();
+ IEnumerable objectList = enumerable.Cast();
return ListOperator switch
{
ListOperator.Any => objectList.Any(o => Children[0].EvaluateObject(o)),
@@ -180,14 +180,14 @@ namespace Artemis.Core
DataModelPath listPath = new DataModelPath(null, Entity.ListPath);
Type listType = listPath.GetPropertyType()!;
// Can't check this on an invalid list, if it becomes valid later lets hope for the best
- if (listPath.IsValid && !typeof(IList).IsAssignableFrom(listType))
+ if (listPath.IsValid && !listPath.PointsToList)
return;
ListPath = listPath;
SubscribeToListPath();
if (ListPath.IsValid)
{
- ListType = listType.GetGenericArguments()[0];
+ ListType = listType.GetGenericEnumerableType();
IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string);
}
else
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
index 1126b8efd..64f62ed68 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
@@ -114,8 +114,14 @@ namespace Artemis.Core
///
/// Gets a boolean indicating whether this data model path points to a list
///
- public bool PointsToList => Segments.LastOrDefault()?.GetPropertyType() != null &&
- typeof(IList).IsAssignableFrom(Segments.LastOrDefault()?.GetPropertyType());
+ public bool PointsToList
+ {
+ get
+ {
+ Type? type = GetPropertyType();
+ return type?.IsGenericEnumerable() ?? false;
+ }
+ }
internal DataModelPathEntity Entity { get; }
diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
index bd33eccc2..b6d68045d 100644
--- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
+++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
@@ -142,79 +142,6 @@ namespace Artemis.Core.DataModelExpansions
return value as T;
}
- internal bool ContainsPath(string? path)
- {
- if (path == null)
- return false;
- string[] parts = path.Split('.');
- Type? current = GetType();
- foreach (string part in parts)
- {
- PropertyInfo? property = current?.GetProperty(part);
- current = property?.PropertyType;
- if (property == null)
- return false;
- }
-
- return true;
- }
-
- internal Type GetTypeAtPath(string path)
- {
- if (!ContainsPath(path))
- return null;
-
- string[] parts = path.Split('.');
- Type current = GetType();
-
- Type result = null;
- foreach (string part in parts)
- {
- PropertyInfo? property = current.GetProperty(part);
- current = property.PropertyType;
- result = property.PropertyType;
- }
-
- return result;
- }
-
- internal Type GetListTypeInPath(string path)
- {
- if (!ContainsPath(path))
- return null;
-
- string[] parts = path.Split('.');
- Type current = GetType();
-
- int index = 0;
- foreach (string part in parts)
- {
- // Only return a type if the path CONTAINS a list, not if it points TO a list
- if (index == parts.Length - 1)
- return null;
-
- PropertyInfo? property = current.GetProperty(part);
-
- // For lists, look into the list type instead of the list itself
- if (typeof(IList).IsAssignableFrom(property.PropertyType))
- return property.PropertyType.GetGenericArguments()[0];
-
- current = property.PropertyType;
- index++;
- }
-
- return null;
- }
-
- internal Type GetListTypeAtPath(string path)
- {
- if (!ContainsPath(path))
- return null;
-
- Type child = GetTypeAtPath(path);
- return child.GenericTypeArguments.Length > 0 ? child.GenericTypeArguments[0] : null;
- }
-
#region Events
///
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
index c0eebd90b..4190752ea 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs
@@ -9,31 +9,38 @@ namespace Artemis.UI.Shared
{
public class DataModelListViewModel : DataModelVisualizationViewModel
{
- private string _count;
- private IList _list;
-
+ private string _countDisplay;
+ private IEnumerable _list;
+ private int _listCount;
+
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
{
ListChildren = new BindableCollection();
}
- public IList List
+ public IEnumerable List
{
get => _list;
set => SetAndNotify(ref _list, value);
}
- public BindableCollection ListChildren { get; set; }
-
- public string Count
+ public int ListCount
{
- get => _count;
- set => SetAndNotify(ref _count, value);
+ get => _listCount;
+ set => SetAndNotify(ref _listCount, value);
}
+ public string CountDisplay
+ {
+ get => _countDisplay;
+ set => SetAndNotify(ref _countDisplay, value);
+ }
+
+ public BindableCollection ListChildren { get; set; }
+
public DataModelPropertiesViewModel GetListTypeViewModel(IDataModelUIService dataModelUIService)
{
- Type listType = DataModelPath.GetPropertyType()?.GenericTypeArguments[0];
+ Type listType = DataModelPath.GetPropertyType()?.GetGenericEnumerableType();
if (listType == null)
return null;
@@ -42,10 +49,8 @@ namespace Artemis.UI.Shared
viewModel.Update(dataModelUIService);
// Put an empty value into the list type property view model
- if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
- {
- return dataModelListClassViewModel;
- }
+ if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel) return dataModelListClassViewModel;
+
if (viewModel is DataModelListPropertyViewModel dataModelListPropertyViewModel)
{
dataModelListPropertyViewModel.DisplayValue = Activator.CreateInstance(dataModelListPropertyViewModel.ListType);
@@ -62,7 +67,7 @@ namespace Artemis.UI.Shared
if (Parent != null && !Parent.IsVisualizationExpanded)
return;
- List = GetCurrentValue() as IList;
+ List = GetCurrentValue() as IEnumerable;
if (List == null)
return;
@@ -71,7 +76,7 @@ namespace Artemis.UI.Shared
{
if (item == null)
continue;
-
+
DataModelVisualizationViewModel child;
if (ListChildren.Count <= index)
{
@@ -79,7 +84,9 @@ namespace Artemis.UI.Shared
ListChildren.Add(child);
}
else
+ {
child = ListChildren[index];
+ }
if (child is DataModelListPropertiesViewModel dataModelListClassViewModel)
{
@@ -96,10 +103,18 @@ namespace Artemis.UI.Shared
index++;
}
- while (ListChildren.Count > List.Count)
+ ListCount = index + 1;
+
+ while (ListChildren.Count > ListCount)
ListChildren.RemoveAt(ListChildren.Count - 1);
- Count = $"{ListChildren.Count} {(ListChildren.Count == 1 ? "item" : "items")}";
+ CountDisplay = $"{ListChildren.Count} {(ListChildren.Count == 1 ? "item" : "items")}";
+ }
+
+ ///
+ public override string ToString()
+ {
+ return $"[List] {DisplayPath ?? Path} - {ListCount} item(s)";
}
protected DataModelVisualizationViewModel CreateListChild(IDataModelUIService dataModelUIService, Type listType)
@@ -117,11 +132,5 @@ namespace Artemis.UI.Shared
return null;
}
-
- ///
- public override string ToString()
- {
- return $"[List] {DisplayPath ?? Path} - {List?.Count ?? 0} item(s)";
- }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
index 9313c0111..8fee846e5 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
@@ -133,7 +133,9 @@ namespace Artemis.UI.Shared
}
if (looseMatch)
- IsMatchingFilteredTypes = filteredTypes.Any(t => t.IsCastableFrom(type) || t == typeof(Enum) && type.IsEnum);
+ IsMatchingFilteredTypes = filteredTypes.Any(t => t.IsCastableFrom(type) ||
+ t == typeof(Enum) && type.IsEnum ||
+ t == typeof(IEnumerable<>) && type.IsGenericEnumerable());
else
IsMatchingFilteredTypes = filteredTypes.Any(t => t == type || t == typeof(Enum) && type.IsEnum);
}
@@ -260,12 +262,12 @@ namespace Artemis.UI.Shared
// For primitives, create a property view model, it may be null that is fine
if (propertyType.IsPrimitive || propertyType.IsEnum || propertyType == typeof(string))
return new DataModelPropertyViewModel(DataModel, this, dataModelPath) {Depth = depth};
- if (typeof(IList).IsAssignableFrom(propertyType))
+ if (propertyType.IsGenericEnumerable())
return new DataModelListViewModel(DataModel, this, dataModelPath) {Depth = depth};
// For other value types create a child view model
if (propertyType.IsClass || propertyType.IsStruct())
return new DataModelPropertiesViewModel(DataModel, this, dataModelPath) {Depth = depth};
-
+
return null;
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
index 5b191e8f8..29fb3a4a6 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
@@ -86,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void Initialize()
{
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
- TargetSelectionViewModel.FilterTypes = new[] {typeof(IList)};
+ TargetSelectionViewModel.FilterTypes = new[] {typeof(IEnumerable<>)};
TargetSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188));
TargetSelectionViewModel.Placeholder = "Select a list";
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
index 15ae774a8..9129116e8 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
@@ -4,7 +4,6 @@ using System.Linq;
using System.Windows;
using System.Windows.Media;
using Artemis.Core;
-using Artemis.Core.DataModelExpansions;
using Artemis.Core.Services;
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
using Artemis.UI.Shared;
@@ -83,19 +82,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public DelegateCommand SelectOperatorCommand { get; }
- public void Dispose()
- {
- if (LeftSideSelectionViewModel != null)
- {
- LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
- LeftSideSelectionViewModel.Dispose();
- LeftSideSelectionViewModel = null;
- }
-
- DisposeRightSideStatic();
- DisposeRightSideDynamic();
- }
-
public override void Delete()
{
base.Delete();
@@ -118,7 +104,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
LeftSideSelectionViewModel.ChangeDataModelPath(DataModelConditionPredicate.LeftPath);
-
+
Type leftSideType = LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
// Get the supported operators
@@ -239,5 +225,18 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideSelectionViewModel = null;
}
}
+
+ public void Dispose()
+ {
+ if (LeftSideSelectionViewModel != null)
+ {
+ LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
+ LeftSideSelectionViewModel.Dispose();
+ LeftSideSelectionViewModel = null;
+ }
+
+ DisposeRightSideStatic();
+ DisposeRightSideDynamic();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml
index f7051ca0f..e0f56aa7b 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml
@@ -69,12 +69,10 @@
-
- [List]
-
+