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

Core - Corrected disposable pattern usage

Core - Further nullable refactoring..
This commit is contained in:
Robert 2020-11-17 20:54:49 +01:00
parent 27e25f22ed
commit b185b28645
38 changed files with 429 additions and 162 deletions

View File

@ -13,7 +13,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DocumentationFile>bin\x64\Debug\Artemis.Core.xml</DocumentationFile>
<NoWarn>1701;1702</NoWarn>
<NoWarn></NoWarn>
<WarningLevel>5</WarningLevel>
</PropertyGroup>
<PropertyGroup>
@ -26,6 +27,7 @@
<NrtRequiredVcs>git</NrtRequiredVcs>
<NrtShowRevision>true</NrtShowRevision>
<Nullable>enable</Nullable>
<AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View File

@ -7,9 +7,9 @@ namespace Artemis.Core
public class DataBinding<TLayerProperty, TProperty> : IDataBinding
{
private TProperty _currentValue = default!;
private TProperty _previousValue = default!;
private bool _disposed;
private TimeSpan _easingProgress;
private TProperty _previousValue = default!;
internal DataBinding(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration)
{
@ -98,6 +98,24 @@ namespace Artemis.Core
return Registration?.PropertyExpression.ReturnType;
}
/// <summary>
/// Updates the smoothing progress of the data binding
/// </summary>
/// <param name="delta">The delta to apply during update</param>
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);
}
/// <summary>
/// Updates the smoothing progress of the data binding
/// </summary>
/// <param name="delta">The delta to apply during update</param>
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;
}
/// <inheritdoc />
public void Apply()
{
@ -175,16 +175,36 @@ namespace Artemis.Core
Converter.ApplyValue(value);
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
if (Registration != null)
Registration.DataBinding = null;
DataBindingMode?.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
if (Registration != null)
Registration.DataBinding = null;
DataBindingMode?.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region Mode management
/// <summary>
@ -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;

View File

@ -43,13 +43,29 @@ namespace Artemis.Core
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
foreach (DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition in Conditions)
dataBindingCondition.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
foreach (DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition in Conditions)
dataBindingCondition.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion

View File

@ -92,12 +92,31 @@ namespace Artemis.Core
Order = Entity.Order;
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
ConditionalDataBinding.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
Condition.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

View File

@ -270,17 +270,37 @@ namespace Artemis.Core
// Parameter is done during initialize
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded;
DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved;
ParameterPath?.Dispose();
}
}
/// <inheritdoc />
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)

View File

@ -54,15 +54,31 @@ namespace Artemis.Core
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
foreach (DataBindingModifier<TLayerProperty, TProperty> dataBindingModifier in Modifiers)
dataBindingModifier.Dispose();
SourcePath?.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
foreach (DataBindingModifier<TLayerProperty, TProperty> dataBindingModifier in Modifiers)
dataBindingModifier.Dispose();
SourcePath?.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion

View File

@ -247,15 +247,31 @@ namespace Artemis.Core
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
Invalidate();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
Invalidate();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion

View File

@ -250,19 +250,35 @@ namespace Artemis.Core
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_dynamicDataModel != null)
{
_dynamicDataModel.DynamicDataModelAdded -= DynamicDataModelOnDynamicDataModelAdded;
_dynamicDataModel.DynamicDataModelRemoved -= DynamicDataModelOnDynamicDataModelRemoved;
}
Type = DataModelPathSegmentType.Invalid;
_accessorLambda = null;
Accessor = null;
}
}
/// <inheritdoc />
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

View File

@ -28,7 +28,7 @@ namespace Artemis.Core
// Cant define generic types as nullable ¯\_(ツ)_/¯
CurrentValue = default!;
DefaultValue = default!;
_baseValue = default!;
_keyframes = new List<LayerPropertyKeyframe<T>>();
}
@ -61,15 +61,35 @@ namespace Artemis.Core
OnUpdated();
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposed = true;
foreach (IDataBinding dataBinding in _dataBindings)
dataBinding.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
foreach (IDataBinding dataBinding in _dataBindings)
dataBinding.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region Hierarchy
private bool _isHidden;

View File

@ -263,16 +263,32 @@ namespace Artemis.Core
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
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();
}
}
/// <inheritdoc />
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

View File

@ -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
/// <inheritdoc />
public override void Update(double deltaTime)
{
lock (this)
lock (_lock)
{
if (Disposed)
throw new ObjectDisposedException("Profile");
@ -79,7 +80,7 @@ namespace Artemis.Core
/// <inheritdoc />
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");

View File

@ -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<BaseLayerEffect> 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();

View File

@ -12,6 +12,7 @@ namespace Artemis.Core
public class Timeline : CorePropertyChanged, IStorageModel
{
private const int MaxExtraTimelines = 15;
private readonly object _lock = new object();
/// <summary>
/// Creates a new instance of the <see cref="Timeline" /> class
@ -19,9 +20,10 @@ namespace Artemis.Core
public Timeline()
{
Entity = new TimelineEntity();
_extraTimelines = new List<Timeline>();
MainSegmentLength = TimeSpan.FromSeconds(5);
_extraTimelines = new List<Timeline>();
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
/// <param name="stickToMainSegment">Whether to stick to the main segment, wrapping around if needed</param>
public void Update(TimeSpan delta, bool stickToMainSegment)
{
lock (this)
lock (_lock)
{
Delta += delta;
Position += delta;
@ -330,7 +333,7 @@ namespace Artemis.Core
/// </summary>
public void JumpToStart()
{
lock (this)
lock (_lock)
{
if (Position == TimeSpan.Zero)
return;
@ -345,7 +348,7 @@ namespace Artemis.Core
/// </summary>
public void JumpToEndSegment()
{
lock (this)
lock (_lock)
{
if (Position >= EndSegmentStartPosition)
return;
@ -360,7 +363,7 @@ namespace Artemis.Core
/// </summary>
public void JumpToEnd()
{
lock (this)
lock (_lock)
{
if (Position >= EndSegmentEndPosition)
return;
@ -377,7 +380,7 @@ namespace Artemis.Core
/// <param name="stickToMainSegment">Whether to stick to the main segment, wrapping around if needed</param>
public void Override(TimeSpan position, bool stickToMainSegment)
{
lock (this)
lock (_lock)
{
Delta += position - Position;
Position = position;
@ -395,7 +398,7 @@ namespace Artemis.Core
/// </summary>
public void ClearDelta()
{
lock (this)
lock (_lock)
{
Delta = TimeSpan.Zero;
}

View File

@ -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
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
DisableLayerBrush();
BaseProperties?.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
DisableLayerBrush();
BaseProperties?.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
/// <summary>

View File

@ -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;

View File

@ -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();

View File

@ -56,7 +56,10 @@ namespace Artemis.Core.LayerBrushes
UpdateLedGroup();
}
internal override void Dispose(bool disposing)
#region IDisposable
/// <inheritdoc />
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();
}

View File

@ -103,13 +103,33 @@ namespace Artemis.Core.LayerEffects
internal string PropertyRootPath => $"LayerEffect.{EntityId}.{GetType().Name}.";
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
DisableLayerEffect();
BaseProperties?.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
DisableLayerEffect();
BaseProperties?.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
/// <summary>
/// Called when the layer effect is activated
/// </summary>

View File

@ -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;

View File

@ -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();

View File

@ -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; }
/// <summary>
/// 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;
}
}

View File

@ -96,6 +96,7 @@ namespace Artemis.Core.Modules
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
/// </summary>
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new List<PropertyInfo>();
private readonly object _lock = new object();
/// <summary>
/// Creates a new instance of the <see cref="ProfileModule" /> 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;

View File

@ -160,19 +160,39 @@ namespace Artemis.Core
}
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
foreach (PluginFeature feature in Features)
feature.Dispose();
Kernel?.Dispose();
PluginLoader?.Dispose();
_features.Clear();
SetEnabled(false);
}
}
/// <inheritdoc />
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
/// <summary>

View File

@ -127,10 +127,30 @@ namespace Artemis.Core
Disable();
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the plugin feature and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Disable();
}
}
#endregion
/// <inheritdoc />
public void Dispose()
{
Disable();
Dispose(true);
GC.SuppressFinalize(this);
}
#region Loading

View File

@ -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<double> 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
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Stop();
Feature.Enabled -= FeatureOnEnabled;
Feature.Disabled -= FeatureOnDisabled;
_disposed = true;
}
}
/// <inheritdoc />
public void Dispose()
{
Stop();
Feature.Enabled -= FeatureOnEnabled;
Feature.Disabled -= FeatureOnDisabled;
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

View File

@ -8,7 +8,7 @@ namespace Artemis.Core
/// <summary>
/// The RGB.NET brush Artemis uses to map the SkiaSharp bitmap to LEDs
/// </summary>
public class BitmapBrush : AbstractDecoratable<IBrushDecorator>, IBrush, IDisposable
public sealed class BitmapBrush : AbstractDecoratable<IBrushDecorator>, IBrush, IDisposable
{
private readonly object _disposeLock;
private readonly PluginSetting<int> _sampleSizeSetting;
@ -67,7 +67,7 @@ namespace Artemis.Core
#region Methods
/// <inheritdoc />
public virtual void PerformRender(Rectangle rectangle, IEnumerable<BrushRenderTarget> renderTargets)
public void PerformRender(Rectangle rectangle, IEnumerable<BrushRenderTarget> renderTargets)
{
lock (_disposeLock)
{
@ -155,7 +155,7 @@ namespace Artemis.Core
}
/// <inheritdoc />
public virtual void PerformFinalize()
public void PerformFinalize()
{
}

View File

@ -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);
}
}
}

View File

@ -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<DeviceEventArgs> DeviceLoaded;
public event EventHandler<DeviceEventArgs> DeviceReloaded;
public event EventHandler<DeviceEventArgs>? DeviceLoaded;
public event EventHandler<DeviceEventArgs>? DeviceReloaded;
public void UpdateSurfaceLedGroup()
{

View File

@ -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);

View File

@ -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)
{

View File

@ -30,7 +30,7 @@ namespace Artemis.Core
/// </summary>
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)

View File

@ -30,7 +30,7 @@ namespace Artemis.Core
/// </summary>
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)

View File

@ -31,7 +31,7 @@ namespace Artemis.Core
/// </summary>
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)

View File

@ -31,7 +31,7 @@ namespace Artemis.Core
/// </summary>
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)

View File

@ -31,7 +31,7 @@ namespace Artemis.Core
/// </summary>
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)

View File

@ -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);

View File

@ -39,8 +39,6 @@ namespace Artemis.UI.Shared
if (parsedIcon == false)
iconEnum = PackIconKind.QuestionMarkCircle;
return iconEnum;
return icon;
}
}
}

View File

@ -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);