diff --git a/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs b/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs
similarity index 53%
rename from src/Artemis.Core/Events/DynamicDataModelEventArgs.cs
rename to src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs
index c1b335adc..61e69c6d1 100644
--- a/src/Artemis.Core/Events/DynamicDataModelEventArgs.cs
+++ b/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs
@@ -4,20 +4,20 @@ using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
///
- /// Provides data about dynamic data model related events
+ /// Provides data about dynamic data model child related events
///
- public class DynamicDataModelEventArgs : EventArgs
+ public class DynamicDataModelChildEventArgs : EventArgs
{
- internal DynamicDataModelEventArgs(DataModel dynamicDataModel, string key)
+ internal DynamicDataModelChildEventArgs(object? dynamicChild, string key)
{
- DynamicDataModel = dynamicDataModel;
+ DynamicChild = dynamicChild;
Key = key;
}
///
- /// Gets the dynamic data model
+ /// Gets the dynamic data model child
///
- public DataModel DynamicDataModel { get; }
+ public object? DynamicChild { get; }
///
/// Gets the key of the dynamic data model on the parent
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
index c8fd98d79..f78bc7c54 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
@@ -15,6 +15,8 @@ namespace Artemis.Core
{
private Expression>? _accessorLambda;
private DataModel? _dynamicDataModel;
+ private Type _dynamicDataModelType;
+ private DataModelPropertyAttribute _dynamicDataModelAttribute;
internal DataModelPathSegment(DataModelPath dataModelPath, string identifier, string path)
{
@@ -49,12 +51,6 @@ namespace Artemis.Core
///
public DataModelPathSegmentType Type { get; private set; }
- ///
- /// Gets the type of dynamic data model this path points to
- /// Not used if the is
- ///
- public Type? DynamicDataModelType { get; private set; }
-
///
/// Gets the previous segment in the path
///
@@ -114,7 +110,7 @@ namespace Artemis.Core
{
// Dynamic types have a data model description
if (Type == DataModelPathSegmentType.Dynamic)
- return (GetValue() as DataModel)?.DataModelDescription;
+ return _dynamicDataModelAttribute;
if (IsStartSegment && DataModelPath.Target != null)
return DataModelPath.Target.DataModelDescription;
if (IsStartSegment)
@@ -187,12 +183,12 @@ namespace Artemis.Core
return CreateExpression(parameter, expression, nullCondition);
// If a dynamic data model is found the use that
- bool hasDynamicDataModel = _dynamicDataModel.DynamicDataModels.TryGetValue(Identifier, out DataModel? dynamicDataModel);
- if (hasDynamicDataModel && dynamicDataModel != null)
- DetermineDynamicType(dynamicDataModel);
+ bool hasDynamicChild = _dynamicDataModel.DynamicChildren.TryGetValue(Identifier, out DynamicChild? dynamicChild);
+ if (hasDynamicChild && dynamicChild?.Value != null)
+ DetermineDynamicType(dynamicChild.Value, dynamicChild.Attribute);
- _dynamicDataModel.DynamicDataModelAdded += DynamicDataModelOnDynamicDataModelAdded;
- _dynamicDataModel.DynamicDataModelRemoved += DynamicDataModelOnDynamicDataModelRemoved;
+ _dynamicDataModel.DynamicChildAdded += DynamicChildOnDynamicChildAdded;
+ _dynamicDataModel.DynamicChildRemoved += DynamicChildOnDynamicChildRemoved;
}
return CreateExpression(parameter, expression, nullCondition);
@@ -219,7 +215,7 @@ namespace Artemis.Core
accessorExpression = Expression.Call(
expression,
nameof(DataModel.DynamicChild),
- DynamicDataModelType != null ? new[] {DynamicDataModelType} : null,
+ _dynamicDataModelType != null ? new[] { _dynamicDataModelType } : null,
Expression.Constant(Identifier)
);
@@ -236,10 +232,11 @@ namespace Artemis.Core
return accessorExpression;
}
- private void DetermineDynamicType(DataModel dynamicDataModel)
+ private void DetermineDynamicType(object dynamicDataModel, DataModelPropertyAttribute attribute)
{
Type = DataModelPathSegmentType.Dynamic;
- DynamicDataModelType = dynamicDataModel.GetType();
+ _dynamicDataModelType = dynamicDataModel.GetType();
+ _dynamicDataModelAttribute = attribute;
}
private void DetermineStaticType(Type previousType)
@@ -263,8 +260,8 @@ namespace Artemis.Core
{
if (_dynamicDataModel != null)
{
- _dynamicDataModel.DynamicDataModelAdded -= DynamicDataModelOnDynamicDataModelAdded;
- _dynamicDataModel.DynamicDataModelRemoved -= DynamicDataModelOnDynamicDataModelRemoved;
+ _dynamicDataModel.DynamicChildAdded -= DynamicChildOnDynamicChildAdded;
+ _dynamicDataModel.DynamicChildRemoved -= DynamicChildOnDynamicChildRemoved;
}
Type = DataModelPathSegmentType.Invalid;
@@ -285,15 +282,15 @@ namespace Artemis.Core
#region Event handlers
- private void DynamicDataModelOnDynamicDataModelAdded(object? sender, DynamicDataModelEventArgs e)
+ private void DynamicChildOnDynamicChildAdded(object? sender, DynamicDataModelChildEventArgs e)
{
if (e.Key == Identifier)
DataModelPath.Initialize();
}
- private void DynamicDataModelOnDynamicDataModelRemoved(object? sender, DynamicDataModelEventArgs e)
+ private void DynamicChildOnDynamicChildRemoved(object? sender, DynamicDataModelChildEventArgs e)
{
- if (e.DynamicDataModel == _dynamicDataModel)
+ if (e.DynamicChild == _dynamicDataModel)
DataModelPath.Initialize();
}
diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
index e207c18eb..392995a4c 100644
--- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
+++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
@@ -14,7 +14,7 @@ namespace Artemis.Core.DataModelExpansions
///
public abstract class DataModel
{
- private readonly Dictionary _dynamicDataModels = new();
+ private readonly Dictionary _dynamicChildren = new();
///
/// Creates a new instance of the class
@@ -47,10 +47,10 @@ namespace Artemis.Core.DataModelExpansions
public bool IsExpansion { get; internal set; }
///
- /// Gets an read-only dictionary of all dynamic data models
+ /// Gets an read-only dictionary of all dynamic children
///
[DataModelIgnore]
- public ReadOnlyDictionary DynamicDataModels => new(_dynamicDataModels);
+ public ReadOnlyDictionary DynamicChildren => new(_dynamicChildren);
///
/// Returns a read-only collection of all properties in this datamodel that are to be ignored
@@ -67,124 +67,211 @@ namespace Artemis.Core.DataModelExpansions
}
///
- /// Adds a dynamic data model to this data model
+ /// Adds a dynamic child to this data model
///
- /// The dynamic data model to add
+ /// The dynamic child to add
/// The key of the child, must be unique to this data model
- /// An optional name, if not provided the key will be used in a humanized form
- /// An optional description
- public T AddDynamicChild(T dynamicDataModel, string key, string? name = null, string? description = null) where T : DataModel
+ /// An optional human readable name, if not provided the key will be used in a humanized form
+ public T AddDynamicChild(T dynamicChild, string key, string? name = null)
{
- if (dynamicDataModel == null)
- throw new ArgumentNullException(nameof(dynamicDataModel));
+ if (dynamicChild == null)
+ throw new ArgumentNullException(nameof(dynamicChild));
if (key == null)
throw new ArgumentNullException(nameof(key));
if (key.Contains('.'))
throw new ArtemisCoreException("The provided key contains an illegal character (.)");
- if (_dynamicDataModels.ContainsKey(key))
- throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " +
- "because the key is already in use on by another dynamic property this data model.");
-
- if (_dynamicDataModels.ContainsValue(dynamicDataModel))
+ if (_dynamicChildren.ContainsKey(key))
{
- string existingKey = _dynamicDataModels.First(kvp => kvp.Value == dynamicDataModel).Key;
- throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " +
- $"because the dynamic data model is already added with key '{existingKey}.");
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
+ "because the key is already in use on by another dynamic property this data model.");
}
if (GetType().GetProperty(key) != null)
- throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " +
+ {
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
"because the key is already in use by a static property on this data model.");
+ }
- dynamicDataModel.Feature = Feature;
- dynamicDataModel.DataModelDescription = new DataModelPropertyAttribute
+ DataModelPropertyAttribute attribute = new()
+ {
+ Name = string.IsNullOrWhiteSpace(name) ? key.Humanize() : name
+ };
+ if (dynamicChild is DataModel dynamicDataModel)
+ {
+ dynamicDataModel.Feature = Feature;
+ dynamicDataModel.DataModelDescription = attribute;
+ }
+
+ _dynamicChildren.Add(key, new DynamicChild(attribute, dynamicChild));
+
+ OnDynamicDataModelAdded(new DynamicDataModelChildEventArgs(dynamicChild, key));
+ return dynamicChild;
+ }
+
+ ///
+ /// Adds a dynamic child to this data model
+ ///
+ /// The dynamic child to add
+ /// The key of the child, must be unique to this data model
+ /// A human readable for your dynamic child, shown in the UI
+ /// An optional description, shown in the UI
+ public T AddDynamicChild(T dynamicChild, string key, string name, string description)
+ {
+ if (dynamicChild == null)
+ throw new ArgumentNullException(nameof(dynamicChild));
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+ if (key.Contains('.'))
+ throw new ArtemisCoreException("The provided key contains an illegal character (.)");
+ if (_dynamicChildren.ContainsKey(key))
+ {
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
+ "because the key is already in use on by another dynamic property this data model.");
+ }
+
+ if (GetType().GetProperty(key) != null)
+ {
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
+ "because the key is already in use by a static property on this data model.");
+ }
+
+ DataModelPropertyAttribute attribute = new()
{
Name = string.IsNullOrWhiteSpace(name) ? key.Humanize() : name,
Description = description
};
- _dynamicDataModels.Add(key, dynamicDataModel);
+ if (dynamicChild is DataModel dynamicDataModel)
+ {
+ dynamicDataModel.Feature = Feature;
+ dynamicDataModel.DataModelDescription = attribute;
+ }
- OnDynamicDataModelAdded(new DynamicDataModelEventArgs(dynamicDataModel, key));
- return dynamicDataModel;
+ _dynamicChildren.Add(key, new DynamicChild(attribute, dynamicChild));
+
+ OnDynamicDataModelAdded(new DynamicDataModelChildEventArgs(dynamicChild, key));
+ return dynamicChild;
}
///
- /// Removes a dynamic data model from the data model by its key
+ /// Adds a dynamic child to this data model
///
- /// The key of the dynamic data model to remove
+ /// The dynamic child to add
+ /// The key of the child, must be unique to this data model
+ /// A data model property attribute describing the dynamic child
+ public T AddDynamicChild(T dynamicChild, string key, DataModelPropertyAttribute attribute)
+ {
+ if (dynamicChild == null) throw new ArgumentNullException(nameof(dynamicChild));
+ if (key == null) throw new ArgumentNullException(nameof(key));
+ if (attribute == null) throw new ArgumentNullException(nameof(attribute));
+ if (key.Contains('.'))
+ throw new ArtemisCoreException("The provided key contains an illegal character (.)");
+ if (_dynamicChildren.ContainsKey(key))
+ {
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
+ "because the key is already in use on by another dynamic property this data model.");
+ }
+
+ if (GetType().GetProperty(key) != null)
+ {
+ throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
+ "because the key is already in use by a static property on this data model.");
+ }
+
+ // Make sure a name is on the attribute or funny things might happen
+ attribute.Name ??= key.Humanize();
+ if (dynamicChild is DataModel dynamicDataModel)
+ {
+ dynamicDataModel.Feature = Feature;
+ dynamicDataModel.DataModelDescription = attribute;
+ }
+
+ _dynamicChildren.Add(key, new DynamicChild(attribute, dynamicChild));
+
+ OnDynamicDataModelAdded(new DynamicDataModelChildEventArgs(dynamicChild, key));
+ return dynamicChild;
+ }
+
+ ///
+ /// Removes a dynamic child from the data model by its key
+ ///
+ /// The key of the dynamic child to remove
public void RemoveDynamicChildByKey(string key)
{
- _dynamicDataModels.TryGetValue(key, out DataModel? childDataModel);
- if (childDataModel == null)
+ if (!_dynamicChildren.TryGetValue(key, out DynamicChild? dynamicChild))
return;
- _dynamicDataModels.Remove(key);
- OnDynamicDataModelRemoved(new DynamicDataModelEventArgs(childDataModel, key));
+ _dynamicChildren.Remove(key);
+ OnDynamicDataModelRemoved(new DynamicDataModelChildEventArgs(dynamicChild.Value, key));
}
///
- /// Removes a dynamic data model from this data model
+ /// Removes a dynamic child from this data model
///
- /// The dynamic data model to remove
- public void RemoveDynamicChild(DataModel dynamicDataModel)
+ /// The dynamic data child to remove
+ public void RemoveDynamicChild(T dynamicChild) where T : class
{
- List keys = _dynamicDataModels.Where(kvp => kvp.Value == dynamicDataModel).Select(kvp => kvp.Key).ToList();
+ List keys = _dynamicChildren.Where(kvp => kvp.Value.Value == dynamicChild).Select(kvp => kvp.Key).ToList();
foreach (string key in keys)
{
- _dynamicDataModels.Remove(key);
- OnDynamicDataModelRemoved(new DynamicDataModelEventArgs(dynamicDataModel, key));
+ _dynamicChildren.Remove(key);
+ OnDynamicDataModelRemoved(new DynamicDataModelChildEventArgs(dynamicChild, key));
}
}
///
- /// Removes all dynamic data models from this data model
+ /// Removes all dynamic children from this data model
///
public void ClearDynamicChildren()
{
- while (_dynamicDataModels.Any())
- RemoveDynamicChildByKey(_dynamicDataModels.First().Key);
+ while (_dynamicChildren.Any())
+ RemoveDynamicChildByKey(_dynamicChildren.First().Key);
}
///
- /// Gets a dynamic data model of type by its key
+ /// Gets a dynamic child of type by its key
///
/// The type of data model you expect
- /// The unique key of the dynamic data model
- /// If found, the dynamic data model otherwise null
- public T? DynamicChild(string key) where T : DataModel
+ /// The unique key of the dynamic child
+ /// If found, the dynamic child otherwise null
+ public T? DynamicChild(string key)
{
- _dynamicDataModels.TryGetValue(key, out DataModel? value);
- return value as T;
- }
+ if (!_dynamicChildren.TryGetValue(key, out DynamicChild? dynamicChild))
+ return default;
- #region Events
-
- ///
- /// Occurs when a dynamic data model has been added to this data model
- ///
- public event EventHandler? DynamicDataModelAdded;
-
- ///
- /// Occurs when a dynamic data model has been removed from this data model
- ///
- public event EventHandler? DynamicDataModelRemoved;
-
- ///
- /// Invokes the event
- ///
- protected virtual void OnDynamicDataModelAdded(DynamicDataModelEventArgs e)
- {
- DynamicDataModelAdded?.Invoke(this, e);
+ if (dynamicChild.Value is not T)
+ return default;
+ return (T?) dynamicChild.Value;
}
///
- /// Invokes the event
+ /// Occurs when a dynamic child has been added to this data model
///
- protected virtual void OnDynamicDataModelRemoved(DynamicDataModelEventArgs e)
+ public event EventHandler? DynamicChildAdded;
+
+ ///
+ /// Occurs when a dynamic child has been removed from this data model
+ ///
+ public event EventHandler? DynamicChildRemoved;
+
+ ///
+ /// Invokes the event
+ ///
+ protected virtual void OnDynamicDataModelAdded(DynamicDataModelChildEventArgs e)
{
- DynamicDataModelRemoved?.Invoke(this, e);
+ DynamicChildAdded?.Invoke(this, e);
}
- #endregion
+ ///
+ /// Invokes the event
+ ///
+ protected virtual void OnDynamicDataModelRemoved(DynamicDataModelChildEventArgs e)
+ {
+ DynamicChildRemoved?.Invoke(this, e);
+ }
}
+
+ ///
+ /// Represents a record of a dynamic child value with its property attribute
+ ///
+ public record DynamicChild(DataModelPropertyAttribute Attribute, object? Value);
}
\ 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 56bbbf5e7..78490468a 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs
@@ -239,9 +239,10 @@ namespace Artemis.UI.Shared
// Add missing dynamic children
object? value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath?.GetValue();
if (value is DataModel dataModel)
- foreach (KeyValuePair kvp in dataModel.DynamicDataModels)
+ {
+ foreach (var (key, dynamicChild) in dataModel.DynamicChildren)
{
- string childPath = AppendToPath(kvp.Key);
+ string childPath = AppendToPath(key);
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
continue;
@@ -249,6 +250,7 @@ namespace Artemis.UI.Shared
if (child != null)
Children.Add(child);
}
+ }
// Remove dynamic children that have been removed from the data model
List toRemoveDynamic = Children.Where(c => c.DataModelPath != null && !c.DataModelPath.IsValid).ToList();