diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj
index e597d75d3..dbfa0a2d6 100644
--- a/src/Artemis.Core/Artemis.Core.csproj
+++ b/src/Artemis.Core/Artemis.Core.csproj
@@ -13,7 +13,8 @@
x64
bin\x64\Debug\Artemis.Core.xml
- 1701;1702
+
+ 5
@@ -26,6 +27,7 @@
git
true
enable
+ latest
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
index 86160eb35..7a31710a4 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
@@ -7,9 +7,9 @@ namespace Artemis.Core
public class DataBinding : IDataBinding
{
private TProperty _currentValue = default!;
- private TProperty _previousValue = default!;
private bool _disposed;
private TimeSpan _easingProgress;
+ private TProperty _previousValue = default!;
internal DataBinding(DataBindingRegistration dataBindingRegistration)
{
@@ -98,6 +98,24 @@ namespace Artemis.Core
return Registration?.PropertyExpression.ReturnType;
}
+ ///
+ /// Updates the smoothing progress of the data binding
+ ///
+ /// The delta to apply during update
+ public void UpdateWithDelta(TimeSpan delta)
+ {
+ if (_disposed)
+ throw new ObjectDisposedException("DataBinding");
+
+ // Data bindings cannot go back in time like brushes
+ if (delta < TimeSpan.Zero)
+ delta = TimeSpan.Zero;
+
+ _easingProgress = _easingProgress.Add(delta);
+ if (_easingProgress > EasingTime)
+ _easingProgress = EasingTime;
+ }
+
private void ResetEasing(TProperty value)
{
_previousValue = GetInterpolatedValue();
@@ -143,24 +161,6 @@ namespace Artemis.Core
UpdateWithDelta(timeline.Delta);
}
- ///
- /// Updates the smoothing progress of the data binding
- ///
- /// The delta to apply during update
- public void UpdateWithDelta(TimeSpan delta)
- {
- if (_disposed)
- throw new ObjectDisposedException("DataBinding");
-
- // Data bindings cannot go back in time like brushes
- if (delta < TimeSpan.Zero)
- delta = TimeSpan.Zero;
-
- _easingProgress = _easingProgress.Add(delta);
- if (_easingProgress > EasingTime)
- _easingProgress = EasingTime;
- }
-
///
public void Apply()
{
@@ -175,16 +175,36 @@ namespace Artemis.Core
Converter.ApplyValue(value);
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ if (Registration != null)
+ Registration.DataBinding = null;
+ DataBindingMode?.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- if (Registration != null)
- Registration.DataBinding = null;
- DataBindingMode?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
#region Mode management
///
@@ -255,7 +275,7 @@ namespace Artemis.Core
LayerProperty.Entity.DataBindingEntities.Add(Entity);
// Don't save an invalid state
- if (Registration != null)
+ if (Registration != null)
Entity.TargetExpression = Registration.PropertyExpression.ToString();
Entity.EasingTime = EasingTime;
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs
index 666e31587..db98a5b86 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/ConditionalDataBinding.cs
@@ -43,13 +43,29 @@ namespace Artemis.Core
#region IDisposable
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ foreach (DataBindingCondition dataBindingCondition in Conditions)
+ dataBindingCondition.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- foreach (DataBindingCondition dataBindingCondition in Conditions)
- dataBindingCondition.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#endregion
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs
index 9be9256e4..c82d8111b 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Conditional/DataBindingCondition.cs
@@ -92,12 +92,31 @@ namespace Artemis.Core
Order = Entity.Order;
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+ ConditionalDataBinding.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- Condition.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs
index b0b10c0e5..49a921fea 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs
@@ -270,17 +270,37 @@ namespace Artemis.Core
// Parameter is done during initialize
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
+ DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
+
+ ParameterPath?.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
- DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
-
- ParameterPath?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
#region Event handlers
private void DataBindingModifierTypeStoreOnDataBindingModifierAdded(object? sender, DataBindingModifierTypeStoreEvent e)
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs
index 03dada505..6dab244f4 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs
@@ -54,15 +54,31 @@ namespace Artemis.Core
#region IDisposable
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ foreach (DataBindingModifier dataBindingModifier in Modifiers)
+ dataBindingModifier.Dispose();
+
+ SourcePath?.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- foreach (DataBindingModifier dataBindingModifier in Modifiers)
- dataBindingModifier.Dispose();
-
- SourcePath?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#endregion
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
index a784716ec..357da89a2 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
@@ -247,15 +247,31 @@ namespace Artemis.Core
#region IDisposable
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
+ DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
+
+ Invalidate();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
- DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
-
- Invalidate();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#endregion
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
index 063a18386..c8fd98d79 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
@@ -250,19 +250,35 @@ namespace Artemis.Core
#region IDisposable
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_dynamicDataModel != null)
+ {
+ _dynamicDataModel.DynamicDataModelAdded -= DynamicDataModelOnDynamicDataModelAdded;
+ _dynamicDataModel.DynamicDataModelRemoved -= DynamicDataModelOnDynamicDataModelRemoved;
+ }
+
+ Type = DataModelPathSegmentType.Invalid;
+
+ _accessorLambda = null;
+ Accessor = null;
+ }
+ }
+
///
public void Dispose()
{
- if (_dynamicDataModel != null)
- {
- _dynamicDataModel.DynamicDataModelAdded -= DynamicDataModelOnDynamicDataModelAdded;
- _dynamicDataModel.DynamicDataModelRemoved -= DynamicDataModelOnDynamicDataModelRemoved;
- }
-
- Type = DataModelPathSegmentType.Invalid;
-
- _accessorLambda = null;
- Accessor = null;
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#endregion
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
index 16b34b8c2..12edfed9c 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
@@ -28,7 +28,7 @@ namespace Artemis.Core
// Cant define generic types as nullable ¯\_(ツ)_/¯
CurrentValue = default!;
DefaultValue = default!;
-
+
_baseValue = default!;
_keyframes = new List>();
}
@@ -61,15 +61,35 @@ namespace Artemis.Core
OnUpdated();
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+
+ foreach (IDataBinding dataBinding in _dataBindings)
+ dataBinding.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
-
- foreach (IDataBinding dataBinding in _dataBindings)
- dataBinding.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
#region Hierarchy
private bool _isHidden;
diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
index 5369ebaf6..2e39f756c 100644
--- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
+++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
@@ -263,16 +263,32 @@ namespace Artemis.Core
#region IDisposable
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _disposed = true;
+ DisableProperties();
+
+ foreach (ILayerProperty layerProperty in _layerProperties)
+ layerProperty.Dispose();
+ foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups)
+ layerPropertyGroup.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- _disposed = true;
- DisableProperties();
-
- foreach (ILayerProperty layerProperty in _layerProperties)
- layerProperty.Dispose();
- foreach (LayerPropertyGroup layerPropertyGroup in _layerPropertyGroups)
- layerPropertyGroup.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#endregion
diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs
index 177d77a50..abadbc421 100644
--- a/src/Artemis.Core/Models/Profile/Profile.cs
+++ b/src/Artemis.Core/Models/Profile/Profile.cs
@@ -13,6 +13,7 @@ namespace Artemis.Core
public sealed class Profile : ProfileElement
{
private bool _isActivated;
+ private readonly object _lock = new object();
internal Profile(ProfileModule module, string name)
{
@@ -64,7 +65,7 @@ namespace Artemis.Core
///
public override void Update(double deltaTime)
{
- lock (this)
+ lock (_lock)
{
if (Disposed)
throw new ObjectDisposedException("Profile");
@@ -79,7 +80,7 @@ namespace Artemis.Core
///
public override void Render(SKCanvas canvas)
{
- lock (this)
+ lock (_lock)
{
if (Disposed)
throw new ObjectDisposedException("Profile");
@@ -182,7 +183,7 @@ namespace Artemis.Core
internal void Activate(ArtemisSurface surface)
{
- lock (this)
+ lock (_lock)
{
if (Disposed)
throw new ObjectDisposedException("Profile");
diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
index 2365c9d9a..53b4cc9b6 100644
--- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
+++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
@@ -287,7 +287,7 @@ namespace Artemis.Core
OnLayerEffectsUpdated();
}
- private void LayerEffectStoreOnLayerEffectRemoved(object sender, LayerEffectStoreEvent e)
+ private void LayerEffectStoreOnLayerEffectRemoved(object? sender, LayerEffectStoreEvent e)
{
// If effects provided by the plugin are on the element, replace them with placeholders
List pluginEffects = LayerEffectsList.Where(ef => ef.Descriptor.Provider != null &&
@@ -303,7 +303,7 @@ namespace Artemis.Core
}
}
- private void LayerEffectStoreOnLayerEffectAdded(object sender, LayerEffectStoreEvent e)
+ private void LayerEffectStoreOnLayerEffectAdded(object? sender, LayerEffectStoreEvent e)
{
if (RenderElementEntity.LayerEffects.Any(ef => ef.ProviderId == e.Registration.PluginFeature.Id))
ActivateEffects();
diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs
index f4bfc52bd..c4e49cc56 100644
--- a/src/Artemis.Core/Models/Profile/Timeline.cs
+++ b/src/Artemis.Core/Models/Profile/Timeline.cs
@@ -12,6 +12,7 @@ namespace Artemis.Core
public class Timeline : CorePropertyChanged, IStorageModel
{
private const int MaxExtraTimelines = 15;
+ private readonly object _lock = new object();
///
/// Creates a new instance of the class
@@ -19,9 +20,10 @@ namespace Artemis.Core
public Timeline()
{
Entity = new TimelineEntity();
- _extraTimelines = new List();
MainSegmentLength = TimeSpan.FromSeconds(5);
+ _extraTimelines = new List();
+
Save();
}
@@ -35,6 +37,7 @@ namespace Artemis.Core
private Timeline(Timeline parent)
{
+ Entity = new TimelineEntity();
Parent = parent;
StartSegmentLength = Parent.StartSegmentLength;
MainSegmentLength = Parent.MainSegmentLength;
@@ -303,7 +306,7 @@ namespace Artemis.Core
/// Whether to stick to the main segment, wrapping around if needed
public void Update(TimeSpan delta, bool stickToMainSegment)
{
- lock (this)
+ lock (_lock)
{
Delta += delta;
Position += delta;
@@ -330,7 +333,7 @@ namespace Artemis.Core
///
public void JumpToStart()
{
- lock (this)
+ lock (_lock)
{
if (Position == TimeSpan.Zero)
return;
@@ -345,7 +348,7 @@ namespace Artemis.Core
///
public void JumpToEndSegment()
{
- lock (this)
+ lock (_lock)
{
if (Position >= EndSegmentStartPosition)
return;
@@ -360,7 +363,7 @@ namespace Artemis.Core
///
public void JumpToEnd()
{
- lock (this)
+ lock (_lock)
{
if (Position >= EndSegmentEndPosition)
return;
@@ -377,7 +380,7 @@ namespace Artemis.Core
/// Whether to stick to the main segment, wrapping around if needed
public void Override(TimeSpan position, bool stickToMainSegment)
{
- lock (this)
+ lock (_lock)
{
Delta += position - Position;
Position = position;
@@ -395,7 +398,7 @@ namespace Artemis.Core
///
public void ClearDelta()
{
- lock (this)
+ lock (_lock)
{
Delta = TimeSpan.Zero;
}
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs
index fd0661a94..837f32142 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs
@@ -97,19 +97,32 @@ namespace Artemis.Core.LayerBrushes
internal abstract void InternalRender(SKCanvas canvas, SKRect path, SKPaint paint);
- internal virtual void Dispose(bool disposing)
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
{
+ if (disposing)
+ {
+ DisableLayerBrush();
+ BaseProperties?.Dispose();
+ }
}
///
public void Dispose()
{
- DisableLayerBrush();
- BaseProperties?.Dispose();
-
Dispose(true);
GC.SuppressFinalize(this);
}
+
+ #endregion
}
///
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs
index 86cac67a7..d8ede59ee 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs
@@ -26,7 +26,7 @@ namespace Artemis.Core.LayerBrushes
{
// I imagine a null reference here can be confusing, so lets throw an exception explaining what to do
if (_properties == null)
- throw new ArtemisPluginException("Cannot access brush properties until OnPropertiesInitialized has been called");
+ throw new InvalidOperationException("Cannot access brush properties until OnPropertiesInitialized has been called");
return _properties;
}
internal set => _properties = value;
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs
index a828c8d25..9b83b0b6b 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs
@@ -46,7 +46,7 @@ namespace Artemis.Core.LayerBrushes
LayerBrushStore.Add(descriptor);
}
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
// The store will clean up the registrations by itself, the plugin just needs to clear its own list
_layerBrushDescriptors.Clear();
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/RgbNetLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/RgbNetLayerBrush.cs
index ee90e8cfa..c106a1c15 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/RgbNetLayerBrush.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/RgbNetLayerBrush.cs
@@ -56,7 +56,10 @@ namespace Artemis.Core.LayerBrushes
UpdateLedGroup();
}
- internal override void Dispose(bool disposing)
+ #region IDisposable
+
+ ///
+ protected override void Dispose(bool disposing)
{
if (disposing)
{
@@ -67,13 +70,15 @@ namespace Artemis.Core.LayerBrushes
base.Dispose(disposing);
}
+ #endregion
+
// Not used in this effect type
internal override void InternalRender(SKCanvas canvas, SKRect bounds, SKPaint paint)
{
throw new NotImplementedException("RGB.NET layer effectes do not implement InternalRender");
}
- private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e)
+ private void LayerOnRenderPropertiesUpdated(object? sender, EventArgs e)
{
UpdateLedGroup();
}
diff --git a/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs
index bff86bdf9..f76014daf 100644
--- a/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs
+++ b/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs
@@ -103,13 +103,33 @@ namespace Artemis.Core.LayerEffects
internal string PropertyRootPath => $"LayerEffect.{EntityId}.{GetType().Name}.";
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DisableLayerEffect();
+ BaseProperties?.Dispose();
+ }
+ }
+
///
public void Dispose()
{
- DisableLayerEffect();
- BaseProperties?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
///
/// Called when the layer effect is activated
///
diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs
index 75bcce09e..585fb8463 100644
--- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs
+++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs
@@ -27,7 +27,7 @@ namespace Artemis.Core.LayerEffects
{
// I imagine a null reference here can be confusing, so lets throw an exception explaining what to do
if (_properties == null)
- throw new ArtemisPluginException("Cannot access effect properties until OnPropertiesInitialized has been called");
+ throw new InvalidOperationException("Cannot access effect properties until OnPropertiesInitialized has been called");
return _properties;
}
internal set => _properties = value;
diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs
index b6b68df7a..7de03159e 100644
--- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs
+++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs
@@ -46,7 +46,7 @@ namespace Artemis.Core.LayerEffects
LayerEffectStore.Add(descriptor);
}
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
// The store will clean up the registrations by itself, the plugin just needs to clear its own list
_layerEffectDescriptors.Clear();
diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs
index 8c3c3ee45..89698c176 100644
--- a/src/Artemis.Core/Plugins/Modules/Module.cs
+++ b/src/Artemis.Core/Plugins/Modules/Module.cs
@@ -140,7 +140,7 @@ namespace Artemis.Core.Modules
internal DataModel? InternalDataModel { get; set; }
internal bool InternalExpandsMainDataModel { get; set; }
- internal ModuleSettingsEntity? Entity { get; set; }
+ internal ModuleSettingsEntity? SettingsEntity { get; set; }
///
/// Called each frame when the module should update
@@ -233,12 +233,12 @@ namespace Artemis.Core.Modules
internal void ApplyToEntity()
{
- if (Entity == null)
- Entity = new ModuleSettingsEntity();
+ if (SettingsEntity == null)
+ SettingsEntity = new ModuleSettingsEntity();
- Entity.ModuleId = Id;
- Entity.PriorityCategory = (int) PriorityCategory;
- Entity.Priority = Priority;
+ SettingsEntity.ModuleId = Id;
+ SettingsEntity.PriorityCategory = (int) PriorityCategory;
+ SettingsEntity.Priority = Priority;
}
}
diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
index 90e04a005..a5b45926c 100644
--- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
+++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
@@ -96,6 +96,7 @@ namespace Artemis.Core.Modules
/// Gets a list of all properties ignored at runtime using IgnoreProperty(x => x.y)
///
protected internal readonly List HiddenPropertiesList = new List();
+ private readonly object _lock = new object();
///
/// Creates a new instance of the class
@@ -154,7 +155,7 @@ namespace Artemis.Core.Modules
if (IsUpdateAllowed)
Update(deltaTime);
- lock (this)
+ lock (_lock)
{
OpacityOverride = AnimatingProfileChange
? Math.Max(0, OpacityOverride - 0.1)
@@ -172,7 +173,7 @@ namespace Artemis.Core.Modules
{
Render(deltaTime, surface, canvas, canvasInfo);
- lock (this)
+ lock (_lock)
{
// Render the profile
ActiveProfile?.Render(canvas);
@@ -210,7 +211,7 @@ namespace Artemis.Core.Modules
if (!IsActivated)
throw new ArtemisCoreException("Cannot activate a profile on a deactivated module");
- lock (this)
+ lock (_lock)
{
if (profile == ActiveProfile)
return;
diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs
index c881ef5fb..2eb977b9d 100644
--- a/src/Artemis.Core/Plugins/Plugin.cs
+++ b/src/Artemis.Core/Plugins/Plugin.cs
@@ -160,19 +160,39 @@ namespace Artemis.Core
}
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ foreach (PluginFeature feature in Features)
+ feature.Dispose();
+
+ Kernel?.Dispose();
+ PluginLoader?.Dispose();
+
+ _features.Clear();
+ SetEnabled(false);
+ }
+ }
+
///
public void Dispose()
{
- foreach (PluginFeature feature in Features)
- feature.Dispose();
-
- Kernel?.Dispose();
- PluginLoader?.Dispose();
-
- _features.Clear();
- SetEnabled(false);
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
#region Events
///
diff --git a/src/Artemis.Core/Plugins/PluginFeature.cs b/src/Artemis.Core/Plugins/PluginFeature.cs
index 06f09b90b..3cc20c092 100644
--- a/src/Artemis.Core/Plugins/PluginFeature.cs
+++ b/src/Artemis.Core/Plugins/PluginFeature.cs
@@ -127,10 +127,30 @@ namespace Artemis.Core
Disable();
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the plugin feature and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Disable();
+ }
+ }
+
+ #endregion
+
///
public void Dispose()
{
- Disable();
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
#region Loading
diff --git a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs
index 9f322c566..cc77111b7 100644
--- a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs
+++ b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs
@@ -13,6 +13,7 @@ namespace Artemis.Core
private DateTime _lastEvent;
private Timer _timer;
private bool _disposed;
+ private readonly object _lock = new object();
internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Action action)
{
@@ -68,7 +69,7 @@ namespace Artemis.Core
if (_disposed)
throw new ObjectDisposedException("TimedUpdateRegistration");
- lock (this)
+ lock (_lock)
{
if (!Feature.IsEnabled)
throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin feature");
@@ -92,7 +93,7 @@ namespace Artemis.Core
if (_disposed)
throw new ObjectDisposedException("TimedUpdateRegistration");
- lock (this)
+ lock (_lock)
{
if (_timer == null)
return;
@@ -109,7 +110,7 @@ namespace Artemis.Core
if (!Feature.IsEnabled)
return;
- lock (this)
+ lock (_lock)
{
TimeSpan interval = DateTime.Now - _lastEvent;
_lastEvent = DateTime.Now;
@@ -138,15 +139,35 @@ namespace Artemis.Core
Stop();
}
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Stop();
+
+ Feature.Enabled -= FeatureOnEnabled;
+ Feature.Disabled -= FeatureOnDisabled;
+
+ _disposed = true;
+ }
+ }
+
///
public void Dispose()
{
- Stop();
-
- Feature.Enabled -= FeatureOnEnabled;
- Feature.Disabled -= FeatureOnDisabled;
-
- _disposed = true;
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/RGB.NET/BitmapBrush.cs b/src/Artemis.Core/RGB.NET/BitmapBrush.cs
index 1bfa5a615..1ac02169d 100644
--- a/src/Artemis.Core/RGB.NET/BitmapBrush.cs
+++ b/src/Artemis.Core/RGB.NET/BitmapBrush.cs
@@ -8,7 +8,7 @@ namespace Artemis.Core
///
/// The RGB.NET brush Artemis uses to map the SkiaSharp bitmap to LEDs
///
- public class BitmapBrush : AbstractDecoratable, IBrush, IDisposable
+ public sealed class BitmapBrush : AbstractDecoratable, IBrush, IDisposable
{
private readonly object _disposeLock;
private readonly PluginSetting _sampleSizeSetting;
@@ -67,7 +67,7 @@ namespace Artemis.Core
#region Methods
///
- public virtual void PerformRender(Rectangle rectangle, IEnumerable renderTargets)
+ public void PerformRender(Rectangle rectangle, IEnumerable renderTargets)
{
lock (_disposeLock)
{
@@ -155,7 +155,7 @@ namespace Artemis.Core
}
///
- public virtual void PerformFinalize()
+ public void PerformFinalize()
{
}
diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs
index 97ccf53ce..d5c543d82 100644
--- a/src/Artemis.Core/Services/ModuleService.cs
+++ b/src/Artemis.Core/Services/ModuleService.cs
@@ -139,11 +139,11 @@ namespace Artemis.Core.Services
ModulePriorityCategory category = module.DefaultPriorityCategory;
int priority = 1;
- module.Entity = _moduleRepository.GetByModuleId(module.Id);
- if (module.Entity != null)
+ module.SettingsEntity = _moduleRepository.GetByModuleId(module.Id);
+ if (module.SettingsEntity != null)
{
- category = (ModulePriorityCategory) module.Entity.PriorityCategory;
- priority = module.Entity.Priority;
+ category = (ModulePriorityCategory) module.SettingsEntity.PriorityCategory;
+ priority = module.SettingsEntity.Priority;
}
UpdateModulePriority(module, category, priority);
@@ -255,10 +255,10 @@ namespace Artemis.Core.Services
categoryModule.Priority = index;
// Don't save modules whose priority hasn't been initialized yet
- if (categoryModule == module || categoryModule.Entity != null)
+ if (categoryModule == module || categoryModule.SettingsEntity != null)
{
categoryModule.ApplyToEntity();
- _moduleRepository.Save(categoryModule.Entity);
+ _moduleRepository.Save(categoryModule.SettingsEntity);
}
}
}
diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs
index 5d096e91f..9091dbdd2 100644
--- a/src/Artemis.Core/Services/RgbService.cs
+++ b/src/Artemis.Core/Services/RgbService.cs
@@ -55,7 +55,7 @@ namespace Artemis.Core.Services
catch (Exception e)
{
_logger.Error(e, "Exception during device loading for device provider {deviceProvider}", deviceProvider.GetType().Name);
- throw e;
+ throw;
}
if (deviceProvider.Devices == null || !deviceProvider.Devices.Any())
@@ -86,12 +86,12 @@ namespace Artemis.Core.Services
Surface.Dispose();
}
- private void RenderScaleSettingOnSettingChanged(object sender, EventArgs e)
+ private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
{
UpdateSurfaceLedGroup();
}
- private void TargetFrameRateSettingOnSettingChanged(object sender, EventArgs e)
+ private void TargetFrameRateSettingOnSettingChanged(object? sender, EventArgs e)
{
UpdateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value;
}
@@ -104,8 +104,8 @@ namespace Artemis.Core.Services
#region Events
- public event EventHandler DeviceLoaded;
- public event EventHandler DeviceReloaded;
+ public event EventHandler? DeviceLoaded;
+ public event EventHandler? DeviceReloaded;
public void UpdateSurfaceLedGroup()
{
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 6ff5a49fd..c1c556618 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -107,12 +107,12 @@ namespace Artemis.Core.Services
Profile profile = new Profile(profileDescriptor.ProfileModule, profileEntity);
InstantiateProfile(profile);
- void ActivatingProfileSurfaceUpdate(object sender, SurfaceConfigurationEventArgs e)
+ void ActivatingProfileSurfaceUpdate(object? sender, SurfaceConfigurationEventArgs e)
{
profile.PopulateLeds(e.Surface);
}
- void ActivatingProfilePluginToggle(object sender, PluginEventArgs e)
+ void ActivatingProfilePluginToggle(object? sender, PluginEventArgs e)
{
InstantiateProfile(profile);
}
@@ -292,12 +292,12 @@ namespace Artemis.Core.Services
#region Event handlers
- private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e)
+ private void OnActiveSurfaceConfigurationSelected(object? sender, SurfaceConfigurationEventArgs e)
{
ActiveProfilesPopulateLeds(e.Surface);
}
- private void OnSurfaceConfigurationUpdated(object sender, SurfaceConfigurationEventArgs e)
+ private void OnSurfaceConfigurationUpdated(object? sender, SurfaceConfigurationEventArgs e)
{
if (e.Surface.IsActive)
ActiveProfilesPopulateLeds(e.Surface);
diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs
index fe0d251eb..af1b2a349 100644
--- a/src/Artemis.Core/Services/Storage/SurfaceService.cs
+++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs
@@ -201,7 +201,7 @@ namespace Artemis.Core.Services
#region Event handlers
- private void RgbServiceOnDeviceLoaded(object sender, DeviceEventArgs e)
+ private void RgbServiceOnDeviceLoaded(object? sender, DeviceEventArgs e)
{
lock (_surfaceConfigurations)
{
@@ -212,7 +212,7 @@ namespace Artemis.Core.Services
UpdateSurfaceConfiguration(ActiveSurface, true);
}
- private void RenderScaleSettingOnSettingChanged(object sender, EventArgs e)
+ private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
{
foreach (ArtemisSurface surfaceConfiguration in SurfaceConfigurations)
{
diff --git a/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs
index 46cb22068..2691ee1ec 100644
--- a/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs
+++ b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs
@@ -30,7 +30,7 @@ namespace Artemis.Core
///
public bool IsInStore { get; internal set; }
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
Plugin.Disabled -= OnDisabled;
if (IsInStore)
diff --git a/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs
index b0ff66088..ddab462bd 100644
--- a/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs
+++ b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs
@@ -30,7 +30,7 @@ namespace Artemis.Core
///
public bool IsInStore { get; internal set; }
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
Plugin.Disabled -= OnDisabled;
if (IsInStore)
diff --git a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs
index 7a1812e02..09c162758 100644
--- a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs
+++ b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs
@@ -31,7 +31,7 @@ namespace Artemis.Core
///
public bool IsInStore { get; internal set; }
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
PluginFeature.Disabled -= OnDisabled;
if (IsInStore)
diff --git a/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs
index 8e35bf905..812a2e836 100644
--- a/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs
+++ b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs
@@ -31,7 +31,7 @@ namespace Artemis.Core
///
public bool IsInStore { get; internal set; }
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
PluginFeature.Disabled -= OnDisabled;
if (IsInStore)
diff --git a/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs
index 0b74524f0..8a53c590a 100644
--- a/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs
+++ b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs
@@ -31,7 +31,7 @@ namespace Artemis.Core
///
public bool IsInStore { get; internal set; }
- private void OnDisabled(object sender, EventArgs e)
+ private void OnDisabled(object? sender, EventArgs e)
{
PluginFeature.Disabled -= OnDisabled;
if (IsInStore)
diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
index e8e91d41f..fd038c6f6 100644
--- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
+++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs
@@ -29,7 +29,7 @@ namespace Artemis.UI.Shared
set => SetAndNotify(ref _listType, value);
}
- public object DisplayValue
+ public new object DisplayValue
{
get => _displayValue;
set => SetAndNotify(ref _displayValue, value);
diff --git a/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs b/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs
index cdf75ad1c..03c5b5cb4 100644
--- a/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs
+++ b/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs
@@ -39,8 +39,6 @@ namespace Artemis.UI.Shared
if (parsedIcon == false)
iconEnum = PackIconKind.QuestionMarkCircle;
return iconEnum;
-
- return icon;
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
index b18d39f74..b7fed07a5 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
@@ -194,27 +194,31 @@ namespace Artemis.UI.Screens.Sidebar
SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.CreateModuleRootViewModel(SidebarModules[sidebarItem]) : null;
}
+ #region IDisposable
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ _activeModulesUpdateTimer?.Dispose();
+ }
+
public void Dispose()
{
- SelectedItem?.Deactivate();
- SelectedItem = null;
-
- _pluginManagementService.PluginFeatureEnabled -= OnFeatureEnabled;
- _pluginManagementService.PluginFeatureDisabled -= OnFeatureDisabled;
-
- _activeModulesUpdateTimer.Stop();
- _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
+ #endregion
+
#region Event handlers
- private void OnFeatureEnabled(object? sender, PluginFeatureEventArgs e)
+ private void OnFeatureEnabled(object sender, PluginFeatureEventArgs e)
{
if (e.PluginFeature is Module module)
AddModule(module);
}
- private void OnFeatureDisabled(object? sender, PluginFeatureEventArgs e)
+ private void OnFeatureDisabled(object sender, PluginFeatureEventArgs e)
{
if (e.PluginFeature is Module module)
RemoveModule(module);