Conditions - Added generic 'changed' event

This commit is contained in:
Robert committed 2021-03-21 12:35:10 +01:00
1 parent 11535508bc
commit 4a9ae697b1
11 files changed
+171 -24

No files matched your search

@@ -12,6 +12,7 @@ namespace Artemis.Core
{
private bool _disposed;
private bool _reinitializing;
private IDataModelEvent? _valueChangedEvent;
/// <summary>
/// Creates a new instance of the <see cref="DataModelConditionEvent" /> class
@@ -56,8 +57,11 @@ namespace Artemis.Core
if (_disposed)
throw new ObjectDisposedException("DataModelConditionEvent");
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
IDataModelEvent? dataModelEvent = GetDataModelEvent();
if (dataModelEvent == null)
return false;
dataModelEvent.Update();
// Only evaluate to true once every time the event has been triggered since the last evaluation
if (dataModelEvent.LastTrigger <= LastTrigger)
return false;
@@ -86,6 +90,7 @@ namespace Artemis.Core
EventPath?.Dispose();
EventPath = path != null ? new DataModelPath(path) : null;
SubscribeToEventPath();
CreateValueChangedEventIfNeeded();
// Remove the old root group that was tied to the old data model
ClearChildren();
@@ -100,6 +105,19 @@ namespace Artemis.Core
{
EventArgumentType = null;
}
LastTrigger = GetDataModelEvent()?.LastTrigger ?? DateTime.Now;
}
/// <summary>
/// Returns the <see cref="IDataModelEvent" /> this <see cref="DataModelConditionEvent" /> is triggered by
/// </summary>
/// <returns>The <see cref="IDataModelEvent" /> this <see cref="DataModelConditionEvent" /> is triggered by</returns>
public IDataModelEvent? GetDataModelEvent()
{
if (_valueChangedEvent != null)
return _valueChangedEvent;
return EventPath?.GetValue() as IDataModelEvent;
}
#region IDisposable
@@ -153,14 +171,10 @@ namespace Artemis.Core
if (Entity.EventPath == null)
return;
// Ensure the list path is valid and points to a list
DataModelPath eventPath = new(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();
CreateValueChangedEventIfNeeded();
EventArgumentType = GetEventArgumentType();
// There should only be one child and it should be a group
@@ -174,8 +188,7 @@ namespace Artemis.Core
AddChild(new DataModelConditionGroup(this));
}
if (EventPath?.GetValue() is IDataModelEvent dataModelEvent)
LastTrigger = dataModelEvent.LastTrigger;
LastTrigger = GetDataModelEvent()?.LastTrigger ?? DateTime.Now;
}
private Type? GetEventArgumentType()
@@ -183,20 +196,14 @@ namespace Artemis.Core
if (EventPath == null || !EventPath.IsValid)
return null;
if (_valueChangedEvent != null)
return _valueChangedEvent.ArgumentsType;
// Cannot rely on EventPath.GetValue() because part of the path might be null
Type eventType = EventPath.GetPropertyType()!;
return eventType.IsGenericType ? eventType.GetGenericArguments()[0] : typeof(DataModelEventArgs);
}
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;
@@ -204,6 +211,23 @@ namespace Artemis.Core
EventPath.PathInvalidated += EventPathOnPathInvalidated;
}
private void CreateValueChangedEventIfNeeded()
{
Type? propertyType = EventPath?.GetPropertyType();
if (propertyType == null)
return;
if (!typeof(IDataModelEvent).IsAssignableFrom(propertyType))
{
IDataModelEvent? instance = (IDataModelEvent?) Activator.CreateInstance(typeof(DataModelValueChangedEvent<>).MakeGenericType(propertyType), EventPath);
_valueChangedEvent = instance ?? throw new ArtemisCoreException("Failed to create a DataModelValueChangedEvent for a property changed data model event");
}
else
{
_valueChangedEvent = null;
}
}
#region Event handlers
private void EventPathOnPathValidated(object? sender, EventArgs e)
@@ -84,6 +84,9 @@ namespace Artemis.Core
[DataModelIgnore]
public Type ArgumentsType => typeof(T);
/// <inheritdoc />
public string TriggerPastParticiple => "triggered";
/// <inheritdoc />
[DataModelIgnore]
public bool TrackHistory
@@ -113,6 +116,11 @@ namespace Artemis.Core
TriggerCount = 0;
EventArgumentsHistory.Clear();
}
/// <inheritdoc />
public void Update()
{
}
}
/// <summary>
@@ -192,6 +200,9 @@ namespace Artemis.Core
[DataModelIgnore]
public Type ArgumentsType => typeof(DataModelEventArgs);
/// <inheritdoc />
public string TriggerPastParticiple => "triggered";
/// <inheritdoc />
[DataModelIgnore]
public bool TrackHistory
@@ -221,5 +232,10 @@ namespace Artemis.Core
TriggerCount = 0;
EventArgumentsHistory.Clear();
}
/// <inheritdoc />
public void Update()
{
}
}
}
@@ -1,4 +1,5 @@
using System;
using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
@@ -10,6 +11,7 @@ namespace Artemis.Core
/// <summary>
/// Gets the time at which the event with these arguments was triggered
/// </summary>
[DataModelIgnore]
public DateTime TriggerTime { get; internal set; }
}
}
@@ -3,7 +3,10 @@ using System.Collections.Generic;
namespace Artemis.Core
{
internal interface IDataModelEvent
/// <summary>
/// Represents a data model event that can trigger <see cref="DataModelConditionEvent" />s.
/// </summary>
public interface IDataModelEvent
{
/// <summary>
/// Gets the last time the event was triggered
@@ -20,6 +23,11 @@ namespace Artemis.Core
/// </summary>
Type ArgumentsType { get; }
/// <summary>
/// Gets the past participle for this event shown in the UI
/// </summary>
string TriggerPastParticiple { get; }
/// <summary>
/// Gets or sets a boolean indicating whether the last 20 events should be tracked
/// <para>Note: setting this to <see langword="false" /> will clear the current history</para>
@@ -46,5 +54,11 @@ namespace Artemis.Core
/// Resets the trigger count and history of this data model event
/// </summary>
void Reset();
/// <summary>
/// Updates the event, not required for standard events but included in case your custom event needs to update every
/// tick
/// </summary>
void Update();
}
}
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
namespace Artemis.Core
{
internal class DataModelValueChangedEvent<T> : IDataModelEvent
{
public DataModelValueChangedEvent(DataModelPath path)
{
Path = path;
}
public DataModelPath Path { get; }
public T? LastValue { get; private set; }
public T? CurrentValue { get; private set; }
public DateTime LastTrigger { get; private set; }
public int TriggerCount { get; private set; }
public Type ArgumentsType { get; } = typeof(DataModelValueChangedEventArgs<T>);
public string TriggerPastParticiple => "changed";
public bool TrackHistory { get; set; } = false;
public DataModelEventArgs? LastEventArgumentsUntyped { get; private set; }
public List<DataModelEventArgs> EventArgumentsHistoryUntyped { get; } = new();
public void Update()
{
object? value = Path.GetValue();
if (value != null)
CurrentValue = (T?) value;
else
CurrentValue = default;
if (!Equals(LastValue, CurrentValue))
Trigger();
LastValue = CurrentValue;
}
public void Reset()
{
TriggerCount = 0;
}
private void Trigger()
{
LastEventArgumentsUntyped = new DataModelValueChangedEventArgs<T>(CurrentValue, LastValue);
LastTrigger = DateTime.Now;
TriggerCount++;
OnEventTriggered();
}
#region Events
public event EventHandler? EventTriggered;
internal virtual void OnEventTriggered()
{
EventTriggered?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}
@@ -0,0 +1,18 @@
using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
internal class DataModelValueChangedEventArgs<T> : DataModelEventArgs
{
public DataModelValueChangedEventArgs(T? currentValue, T? previousValue)
{
CurrentValue = currentValue;
PreviousValue = previousValue;
}
[DataModelProperty(Description = "The current value of the property")]
public T? CurrentValue { get; }
[DataModelProperty(Description = "The previous value of the property")]
public T? PreviousValue { get; }
}
}