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

Data model events - WIP commit

This commit is contained in:
SpoinkyNL 2020-10-21 22:37:24 +02:00
parent b8112601df
commit 03b0e83ed8
19 changed files with 554 additions and 28 deletions

View File

@ -13,20 +13,30 @@ namespace Artemis.Core
/// <param name="a">The parameter on the left side of the expression</param>
/// <param name="b">The parameter on the right side of the expression</param>
public abstract bool Evaluate(TLeftSide a, TRightSide b);
/// <inheritdoc />
internal override bool InternalEvaluate(object? leftSideValue, object? rightSideValue)
{
// TODO: Can we avoid boxing/unboxing?
TLeftSide leftSide;
if (leftSideValue != null)
leftSide = (TLeftSide) Convert.ChangeType(leftSideValue, typeof(TLeftSide));
{
if (leftSideValue.GetType() != typeof(TLeftSide))
leftSide = (TLeftSide) Convert.ChangeType(leftSideValue, typeof(TLeftSide));
else
leftSide = (TLeftSide) leftSideValue;
}
else
leftSide = default;
TRightSide rightSide;
if (rightSideValue != null)
rightSide = (TRightSide) Convert.ChangeType(rightSideValue, typeof(TRightSide));
{
if (rightSideValue.GetType() != typeof(TRightSide))
rightSide = (TRightSide) Convert.ChangeType(rightSideValue, typeof(TRightSide));
else
rightSide = (TRightSide) rightSideValue;
}
else
rightSide = default;
@ -57,7 +67,12 @@ namespace Artemis.Core
// TODO: Can we avoid boxing/unboxing?
TLeftSide leftSide;
if (leftSideValue != null)
leftSide = (TLeftSide) Convert.ChangeType(leftSideValue, typeof(TLeftSide));
{
if (leftSideValue.GetType() != typeof(TLeftSide))
leftSide = (TLeftSide)Convert.ChangeType(leftSideValue, typeof(TLeftSide));
else
leftSide = (TLeftSide)leftSideValue;
}
else
leftSide = default;

View File

@ -0,0 +1,189 @@
using System;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core
{
/// <summary>
/// A condition that evaluates to true when an event is triggered
/// </summary>
public class DataModelConditionEvent : DataModelConditionPart
{
private bool _disposed;
private bool _reinitializing;
private IDataModelEvent? _event;
private bool _eventTriggered;
/// <summary>
/// Creates a new instance of the <see cref="DataModelConditionEvent" /> class
/// </summary>
/// <param name="parent"></param>
public DataModelConditionEvent(DataModelConditionPart parent)
{
Parent = parent;
Entity = new DataModelConditionEventEntity();
Initialize();
}
internal DataModelConditionEvent(DataModelConditionPart parent, DataModelConditionEventEntity entity)
{
Parent = parent;
Entity = entity;
Initialize();
}
/// <summary>
/// Gets the path of the event property
/// </summary>
public DataModelPath? EventPath { get; private set; }
internal DataModelConditionEventEntity Entity { get; set; }
/// <inheritdoc />
public override bool Evaluate()
{
if (_disposed)
throw new ObjectDisposedException("DataModelConditionEvent");
// Ensure the event has not been replaced
if (EventPath?.GetValue() is IDataModelEvent dataModelEvent && _event != dataModelEvent)
SubscribeToDataModelEvent(dataModelEvent);
// Only evaluate to true once every time the event has been triggered
if (!_eventTriggered)
return false;
_eventTriggered = false;
return true;
}
private void SubscribeToDataModelEvent(IDataModelEvent dataModelEvent)
{
if (_event != null)
_event.EventTriggered -= OnEventTriggered;
_event = dataModelEvent;
if (_event != null)
_event.EventTriggered += OnEventTriggered;
}
/// <summary>
/// Updates the event the condition is triggered by
/// </summary>
public void UpdateEvent(DataModelPath? path)
{
if (_disposed)
throw new ObjectDisposedException("DataModelConditionEvent");
if (path != null && !path.IsValid)
throw new ArtemisCoreException("Cannot update event to an invalid path");
EventPath?.Dispose();
EventPath = path != null ? new DataModelPath(path) : null;
SubscribeToEventPath();
}
#region IDisposable
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
_disposed = true;
EventPath?.Dispose();
foreach (DataModelConditionPart child in Children)
child.Dispose();
base.Dispose(disposing);
}
#endregion
internal override bool EvaluateObject(object target)
{
return false;
}
internal override void Save()
{
// Don't save an invalid state
if (EventPath != null && !EventPath.IsValid)
return;
// Target list
EventPath?.Save();
Entity.EventPath = EventPath?.Entity;
}
internal override DataModelConditionPartEntity GetEntity()
{
return Entity;
}
internal void Initialize()
{
if (Entity.EventPath == null)
return;
// Ensure the list path is valid and points to a list
DataModelPath eventPath = new DataModelPath(null, Entity.EventPath);
// Can't check this on an invalid list, if it becomes valid later lets hope for the best
if (eventPath.IsValid && !PointsToEvent(eventPath))
return;
EventPath = eventPath;
SubscribeToEventPath();
}
private bool PointsToEvent(DataModelPath dataModelPath)
{
Type? type = dataModelPath.GetPropertyType();
if (type == null)
return false;
return typeof(IDataModelEvent).IsAssignableFrom(type);
}
private void SubscribeToEventPath()
{
if (EventPath == null) return;
EventPath.PathValidated += EventPathOnPathValidated;
EventPath.PathInvalidated += EventPathOnPathInvalidated;
}
#region Event handlers
private void OnEventTriggered(object? sender, EventArgs e)
{
_eventTriggered = true;
}
private void EventPathOnPathValidated(object? sender, EventArgs e)
{
if (_reinitializing)
return;
_reinitializing = true;
EventPath?.Dispose();
Initialize();
_reinitializing = false;
}
private void EventPathOnPathInvalidated(object? sender, EventArgs e)
{
if (_reinitializing)
return;
_reinitializing = true;
EventPath?.Dispose();
Initialize();
_reinitializing = false;
}
#endregion
}
}

View File

@ -180,7 +180,7 @@ 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 && !listPath.PointsToList)
if (listPath.IsValid && !PointsToList(listPath))
return;
ListPath = listPath;
@ -208,6 +208,12 @@ namespace Artemis.Core
}
}
private bool PointsToList(DataModelPath dataModelPath)
{
Type? type = dataModelPath.GetPropertyType();
return type?.IsGenericEnumerable() ?? false;
}
private void SubscribeToListPath()
{
if (ListPath == null) return;

View File

@ -0,0 +1,85 @@
using System;
using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
/// <summary>
/// Represents a data model event with event arguments of type <typeparamref name="T" />
/// </summary>
public class DataModelEvent<T> : IDataModelEvent where T : DataModelEventArgs
{
/// <summary>
/// Trigger the event with the given <paramref name="eventArgs" />
/// </summary>
/// <param name="eventArgs">The event argument to pass to the event</param>
public void Trigger(T eventArgs)
{
if (eventArgs == null) throw new ArgumentNullException(nameof(eventArgs));
eventArgs.TriggerTime = DateTime.Now;
LastEventArguments = eventArgs;
LastTrigger = DateTime.Now;
TriggerCount++;
OnEventTriggered();
}
internal virtual void OnEventTriggered()
{
EventTriggered?.Invoke(this, EventArgs.Empty);
}
/// <inheritdoc />
public DateTime LastTrigger { get; private set; }
/// <inheritdoc />
public int TriggerCount { get; private set; }
/// <summary>
/// Gets the event arguments of the last time the event was triggered
/// </summary>
public T? LastEventArguments { get; private set; }
/// <inheritdoc />
[DataModelIgnore]
public Type ArgumentsType => typeof(T);
/// <inheritdoc />
public event EventHandler? EventTriggered;
}
/// <summary>
/// Represents a data model event without event arguments
/// </summary>
public class DataModelEvent : IDataModelEvent
{
/// <summary>
/// Trigger the event
/// </summary>
public void Trigger()
{
LastTrigger = DateTime.Now;
TriggerCount++;
OnEventTriggered();
}
internal virtual void OnEventTriggered()
{
EventTriggered?.Invoke(this, EventArgs.Empty);
}
/// <inheritdoc />
public DateTime LastTrigger { get; private set; }
/// <inheritdoc />
public int TriggerCount { get; private set; }
/// <inheritdoc />
[DataModelIgnore]
public Type? ArgumentsType => null;
/// <inheritdoc />
public event EventHandler? EventTriggered;
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace Artemis.Core
{
/// <summary>
/// Represents the base class for data model events that contain event data
/// </summary>
public class DataModelEventArgs
{
/// <summary>
/// Gets the time at which the event with these arguments was triggered
/// </summary>
public DateTime TriggerTime { get; internal set; }
}
}

View File

@ -111,18 +111,6 @@ namespace Artemis.Core
/// </summary>
public IReadOnlyCollection<DataModelPathSegment> Segments => _segments.ToList().AsReadOnly();
/// <summary>
/// Gets a boolean indicating whether this data model path points to a list
/// </summary>
public bool PointsToList
{
get
{
Type? type = GetPropertyType();
return type?.IsGenericEnumerable() ?? false;
}
}
internal DataModelPathEntity Entity { get; }
internal Func<object, object>? Accessor { get; private set; }

View File

@ -0,0 +1,27 @@
using System;
namespace Artemis.Core
{
internal interface IDataModelEvent
{
/// <summary>
/// Gets the last time the event was triggered
/// </summary>
DateTime LastTrigger { get; }
/// <summary>
/// Gets the amount of times the event was triggered
/// </summary>
int TriggerCount { get; }
/// <summary>
/// Gets the type of arguments this event contains
/// </summary>
Type? ArgumentsType { get; }
/// <summary>
/// Fires when the event is triggered
/// </summary>
event EventHandler EventTriggered;
}
}

View File

@ -0,0 +1,14 @@
using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Storage.Entities.Profile.Conditions
{
public class DataModelConditionEventEntity : DataModelConditionPartEntity
{
public DataModelConditionEventEntity()
{
}
public DataModelPathEntity EventPath { get; set; }
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Storage.Entities.Profile.Conditions

View File

@ -1,2 +1,14 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=behaviors/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controls/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=converters/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datamodelvisualization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datamodelvisualization_005Cshared/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dependencyproperties/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=propertyinput/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cdatamodelvisualization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cdialog/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cinterfaces/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utilities/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,33 @@
using Artemis.Core;
using Artemis.Core.DataModelExpansions;
using Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared
{
public class DataModelEventViewModel : DataModelVisualizationViewModel
{
internal DataModelEventViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
{
}
public override void Update(IDataModelUIService dataModelUIService)
{
}
public override object GetCurrentValue()
{
return null;
}
/// <inheritdoc />
public override string ToString()
{
return DisplayPath ?? Path;
}
internal override int GetChildDepth()
{
return PropertyDescription != null && !PropertyDescription.ResetsDepth ? Depth + 1 : 1;
}
}
}

View File

@ -7,8 +7,8 @@ namespace Artemis.UI.Shared
{
public class DataModelPropertiesViewModel : DataModelVisualizationViewModel
{
private Type _displayValueType;
private object _displayValue;
private Type _displayValueType;
internal DataModelPropertiesViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
{
@ -29,15 +29,15 @@ namespace Artemis.UI.Shared
public override void Update(IDataModelUIService dataModelUIService)
{
DisplayValueType = DataModelPath?.GetPropertyType();
// Only set a display value if ToString returns useful information and not just the type name
object currentValue = GetCurrentValue();
if (currentValue != null && currentValue.ToString() != currentValue.GetType().ToString())
DisplayValue = currentValue.ToString();
else
DisplayValue = null;
// Always populate properties
// Always populate properties
PopulateProperties(dataModelUIService);
// Only update children if the parent is expanded

View File

@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
@ -137,7 +136,8 @@ namespace Artemis.UI.Shared
if (looseMatch)
IsMatchingFilteredTypes = filteredTypes.Any(t => t.IsCastableFrom(type) ||
t == typeof(Enum) && type.IsEnum ||
t == typeof(IEnumerable<>) && type.IsGenericEnumerable());
t == typeof(IEnumerable<>) && type.IsGenericEnumerable() ||
type.IsGenericType && t == type.GetGenericTypeDefinition());
else
IsMatchingFilteredTypes = filteredTypes.Any(t => t == type || t == typeof(Enum) && type.IsEnum);
}
@ -219,7 +219,6 @@ namespace Artemis.UI.Shared
// Add missing dynamic children
object value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
if (value is DataModel dataModel)
{
foreach (KeyValuePair<string, DataModel> kvp in dataModel.DynamicDataModels)
{
string childPath = AppendToPath(kvp.Key);
@ -230,7 +229,6 @@ namespace Artemis.UI.Shared
if (child != null)
Children.Add(child);
}
}
// Remove dynamic children that have been removed from the data model
List<DataModelVisualizationViewModel> toRemoveDynamic = Children.Where(c => !c.DataModelPath.IsValid).ToList();
@ -266,6 +264,8 @@ namespace Artemis.UI.Shared
return new DataModelPropertyViewModel(DataModel, this, dataModelPath) {Depth = depth};
if (propertyType.IsGenericEnumerable())
return new DataModelListViewModel(DataModel, this, dataModelPath) {Depth = depth};
if (propertyType == typeof(DataModelEvent) || propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(DataModelEvent<>))
return new DataModelEventViewModel(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};

View File

@ -39,6 +39,12 @@
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="LightningBolt" VerticalAlignment="Center" Margin="0 0 5 0" />
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="Trigger layer on event" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid>
<!-- Value description -->
@ -73,6 +79,12 @@
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="LightningBolt" VerticalAlignment="Center" Margin="0 0 5 0" />
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid ToolTip="{Binding PropertyDescription.Description}">
<Grid.ColumnDefinitions>

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using Artemis.Core;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Input;
using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
public class DataModelConditionEventViewModel : DataModelConditionViewModel, IDisposable
{
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService;
private DataModelDynamicViewModel _targetSelectionViewModel;
public DataModelConditionEventViewModel(DataModelConditionEvent model,
IProfileEditorService profileEditorService,
IDataModelUIService dataModelUIService,
IDataModelConditionsVmFactory dataModelConditionsVmFactory) : base(model)
{
_profileEditorService = profileEditorService;
_dataModelUIService = dataModelUIService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
Initialize();
}
public DataModelConditionEvent DataModelConditionEvent => (DataModelConditionEvent) Model;
public DataModelDynamicViewModel TargetSelectionViewModel
{
get => _targetSelectionViewModel;
set => SetAndNotify(ref _targetSelectionViewModel, value);
}
public void Initialize()
{
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
List<Type> supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
supportedInputTypes.Add(typeof(IEnumerable<>));
TargetSelectionViewModel.FilterTypes = supportedInputTypes.ToArray();
TargetSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(188, 174, 71));
TargetSelectionViewModel.Placeholder = "Select a list";
Update();
}
public void ApplyEvent()
{
if (!TargetSelectionViewModel.DataModelPath.GetPropertyType().IsGenericEnumerable())
{
if (Parent is DataModelConditionGroupViewModel groupViewModel)
groupViewModel.ConvertToPredicate(this);
return;
}
DataModelConditionEvent.UpdateEvent(TargetSelectionViewModel.DataModelPath);
_profileEditorService.UpdateSelectedProfileElement();
Update();
}
#region Event handlers
private void TargetSelectionViewModelOnPropertySelected(object? sender, DataModelInputDynamicEventArgs e)
{
ApplyEvent();
}
#endregion
#region IDisposable
public void Dispose()
{
TargetSelectionViewModel.Dispose();
TargetSelectionViewModel.PropertySelected -= TargetSelectionViewModelOnPropertySelected;
}
#endregion
}
}

View File

@ -147,6 +147,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
Update();
}
public void ConvertToConditionEvent(DataModelConditionPredicateViewModel predicateViewModel)
{
// Remove the old child
DataModelConditionGroup.RemoveChild(predicateViewModel.Model);
DataModelConditionPart rootGroup = DataModelConditionGroup;
while (rootGroup.Parent != null)
rootGroup = rootGroup.Parent;
// Insert an event at the start of the root group
DataModelConditionEvent conditionEvent = new DataModelConditionEvent(rootGroup);
conditionEvent.UpdateEvent(predicateViewModel.LeftSideSelectionViewModel.DataModelPath);
rootGroup.AddChild(conditionEvent, 0);
// Update to switch the VMs
Update();
}
public void ConvertToPredicate(DataModelConditionListViewModel listViewModel)
{
// Store the old index and remove the old predicate

View File

@ -97,6 +97,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
_supportedInputTypes.Add(typeof(IEnumerable<>));
_supportedInputTypes.Add(typeof(DataModelEvent));
_supportedInputTypes.Add(typeof(DataModelEvent<>));
Update();
}
@ -278,7 +280,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
Update();
}
private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
{
DataModelConditionPredicate.PredicateType = ProfileRightSideType.Dynamic;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Artemis.Core;
using Artemis.Core.DataModelExpansions;
using SkiaSharp;
@ -34,6 +35,22 @@ namespace Artemis.Plugins.DataModelExpansions.TestData.DataModels
public bool IsWinning { get; set; }
public List<SomeListItem> ListItems { get; set; }
[DataModelProperty(Description = "Event without arguments")]
public DataModelEvent Event1 { get; set; } = new DataModelEvent();
[DataModelProperty(Description = "Event with arguments")]
public DataModelEvent<TestEventArgs> Event2 { get; set; } = new DataModelEvent<TestEventArgs>();
}
public class TestEventArgs : DataModelEventArgs
{
public TestEventArgs(string someValue)
{
SomeValue = someValue;
}
public string SomeValue { get; set; }
}
public class Test<T>

View File

@ -23,6 +23,8 @@ namespace Artemis.Plugins.DataModelExpansions.TestData
{
// You can access your data model here and update it however you like
DataModel.TemplateDataModelString = $"The last delta time was {deltaTime} seconds";
// DataModel.Event1.Trigger();
}
private void TimedUpdate(double deltaTime)