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

UI - Restructured layer property VMs

This commit is contained in:
Robert 2020-05-01 23:07:21 +02:00
parent 41b3c77210
commit 54081b591b
11 changed files with 163 additions and 234 deletions

View File

@ -125,7 +125,7 @@ namespace Artemis.Core.Models.Profile
General.ApplyToEntity();
Transform.ApplyToEntity();
LayerBrush.ApplyToEntity();
LayerBrush.BaseProperties.ApplyToEntity();
// LEDs
LayerEntity.Leds.Clear();
@ -187,7 +187,7 @@ namespace Artemis.Core.Models.Profile
var properties = new List<BaseLayerProperty>(General.GetAllLayerProperties());
properties.AddRange(Transform.GetAllLayerProperties());
properties.AddRange(LayerBrush.GetAllLayerProperties());
properties.AddRange(LayerBrush.BaseProperties.GetAllLayerProperties());
// For now, reset all keyframe engines after the last keyframe was hit
// This is a placeholder method of repeating the animation until repeat modes are implemented
@ -196,13 +196,13 @@ namespace Artemis.Core.Models.Profile
{
General.Override(TimeSpan.Zero);
Transform.Override(TimeSpan.Zero);
LayerBrush.OverrideProperties(TimeSpan.Zero);
LayerBrush.BaseProperties.Override(TimeSpan.Zero);
}
else
{
General.Update(deltaTime);
Transform.Update(deltaTime);
LayerBrush.UpdateProperties(deltaTime);
LayerBrush.BaseProperties.Update(deltaTime);
}
LayerBrush.Update(deltaTime);
@ -212,7 +212,7 @@ namespace Artemis.Core.Models.Profile
{
General.Override(timeOverride);
Transform.Override(timeOverride);
LayerBrush.OverrideProperties(timeOverride);
LayerBrush.BaseProperties.Override(timeOverride);
}
/// <inheritdoc />

View File

@ -5,7 +5,7 @@ using Artemis.Storage.Entities.Profile;
namespace Artemis.Core.Models.Profile.LayerProperties
{
/// <summary>
/// For internal use only, to implement your own layer property type, extend <see cref="LayerProperty{T}"/> instead.
/// For internal use only, to implement your own layer property type, extend <see cref="LayerProperty{T}" /> instead.
/// </summary>
public abstract class BaseLayerProperty
{
@ -42,11 +42,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// <summary>
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
/// </summary>
internal bool IsCoreProperty { get; set; }
public bool IsCoreProperty { get; internal set; }
/// <summary>
/// Gets a list of all the keyframes in their non-generic base form, without their values being available
/// </summary>
public abstract IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes { get; }
internal PropertyEntity PropertyEntity { get; set; }
internal LayerPropertyGroup LayerPropertyGroup { get; set; }
internal abstract IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes { get; }
/// <summary>
/// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values

View File

@ -70,7 +70,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public LayerPropertyKeyframe<T> NextKeyframe { get; protected set; }
internal override IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes => _keyframes.Cast<BaseLayerPropertyKeyframe>().ToList().AsReadOnly();
public override IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes => _keyframes.Cast<BaseLayerPropertyKeyframe>().ToList().AsReadOnly();
/// <summary>
/// Adds a keyframe to the layer property

View File

@ -14,29 +14,34 @@ namespace Artemis.Core.Models.Profile
public class LayerPropertyGroup
{
private ReadOnlyCollection<BaseLayerProperty> _allLayerProperties;
private readonly List<BaseLayerProperty> _layerProperties;
private readonly List<LayerPropertyGroup> _layerPropertyGroups;
protected LayerPropertyGroup()
{
LayerProperties = new List<BaseLayerProperty>();
LayerPropertyGroups = new List<LayerPropertyGroup>();
_layerProperties = new List<BaseLayerProperty>();
_layerPropertyGroups = new List<LayerPropertyGroup>();
}
/// <summary>
/// Gets whether this property group's properties are all initialized
/// </summary>
public bool PropertiesInitialized { get; private set; }
/// <summary>
/// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID
/// </summary>
internal bool IsCorePropertyGroup { get; set; }
public bool IsCorePropertyGroup { get; internal set; }
/// <summary>
/// A list of all layer properties in this group
/// </summary>
internal List<BaseLayerProperty> LayerProperties { get; set; }
public ReadOnlyCollection<BaseLayerProperty> LayerProperties => _layerProperties.AsReadOnly();
/// <summary>
/// A list of al child groups in this group
/// </summary>
internal List<LayerPropertyGroup> LayerPropertyGroups { get; set; }
public ReadOnlyCollection<LayerPropertyGroup> LayerPropertyGroups => _layerPropertyGroups.AsReadOnly();
/// <summary>
/// Called when all layer properties in this property group have been initialized
@ -63,7 +68,7 @@ namespace Artemis.Core.Models.Profile
var instance = (BaseLayerProperty) Activator.CreateInstance(propertyInfo.PropertyType);
InitializeProperty(layer, path, instance);
propertyInfo.SetValue(this, instance);
LayerProperties.Add(instance);
_layerProperties.Add(instance);
}
else
{
@ -76,7 +81,7 @@ namespace Artemis.Core.Models.Profile
var instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType);
instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}.");
propertyInfo.SetValue(this, instance);
LayerPropertyGroups.Add(instance);
_layerPropertyGroups.Add(instance);
}
}
}
@ -121,7 +126,7 @@ namespace Artemis.Core.Models.Profile
/// Recursively gets all layer properties on this group and any subgroups
/// </summary>
/// <returns></returns>
internal IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
public IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{
if (!PropertiesInitialized)
return new List<BaseLayerProperty>();

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces;
using SkiaSharp;
@ -29,7 +27,7 @@ namespace Artemis.Core.Plugins.LayerBrush
/// </summary>
public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo;
internal virtual LayerPropertyGroup BaseProperties => null;
public virtual LayerPropertyGroup BaseProperties => null;
/// <summary>
/// Called when the brush is being removed from the layer
@ -62,22 +60,5 @@ namespace Artemis.Core.Plugins.LayerBrush
internal virtual void InitializeProperties(ILayerService layerService, string path)
{
}
internal virtual void ApplyToEntity()
{
}
internal virtual void UpdateProperties(double deltaTime)
{
}
internal virtual void OverrideProperties(TimeSpan overrideTime)
{
}
internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{
return new List<BaseLayerProperty>();
}
}
}

View File

@ -47,7 +47,7 @@ namespace Artemis.Core.Plugins.LayerBrush
}
/// <inheritdoc/>
internal override LayerPropertyGroup BaseProperties => Properties;
public override LayerPropertyGroup BaseProperties => Properties;
internal override void InitializeProperties(ILayerService layerService, string path)
{
@ -56,22 +56,17 @@ namespace Artemis.Core.Plugins.LayerBrush
PropertiesInitialized = true;
}
internal override void ApplyToEntity()
internal virtual void ApplyToEntity()
{
Properties.ApplyToEntity();
}
internal override void UpdateProperties(double deltaTime)
{
Properties.Update(deltaTime);
}
internal override void OverrideProperties(TimeSpan overrideTime)
internal virtual void OverrideProperties(TimeSpan overrideTime)
{
Properties.Override(overrideTime);
}
internal override IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{
return Properties.GetAllLayerProperties();
}

View File

@ -76,10 +76,5 @@ namespace Artemis.Core.Services
layer.LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid);
}
public void GetLayerPropertyGroups(Layer layer)
{
var groups = new List<LayerPropertyGroup> {layer.General, layer.Transform, layer.LayerBrush.BrushProperties};
}
}
}

View File

@ -0,0 +1,11 @@
using System.Collections.Generic;
using Artemis.Core.Models.Profile.LayerProperties;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract
{
public abstract class LayerPropertyBaseViewModel : PropertyChangedBase
{
public abstract List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly);
}
}

View File

@ -7,6 +7,7 @@ using System.Windows.Media;
using Artemis.Core.Events;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Services;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Events;
@ -21,28 +22,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
{
private readonly ICoreService _coreService;
private readonly List<LayerPropertyViewModel> _layerPropertyViewModels;
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private readonly IPropertyTreeVmFactory _propertyTreeVmFactory;
private readonly IPropertyTimelineVmFactory _propertyTimelineVmFactory;
private readonly IProfileEditorService _profileEditorService;
private readonly ISettingsService _settingsService;
private Layer _lastSelectedLayer;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService,
ICoreService coreService,
ISettingsService settingsService,
ILayerPropertyVmFactory layerPropertyVmFactory,
IPropertyTreeVmFactory propertyTreeVmFactory,
IPropertyTimelineVmFactory propertyTimelineVmFactory)
{
_profileEditorService = profileEditorService;
_coreService = coreService;
_settingsService = settingsService;
_layerPropertyVmFactory = layerPropertyVmFactory;
_propertyTreeVmFactory = propertyTreeVmFactory;
_propertyTimelineVmFactory = propertyTimelineVmFactory;
_layerPropertyViewModels = new List<LayerPropertyViewModel>();
PixelsPerSecond = 31;
}
@ -67,6 +62,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
set => _profileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / PixelsPerSecond);
}
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
public PropertyTreeViewModel PropertyTree { get; set; }
public PropertyTimelineViewModel PropertyTimeline { get; set; }
@ -88,12 +84,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
_profileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
if (_lastSelectedLayer != null)
{
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
}
PropertyTree?.Dispose();
PropertyTimeline?.Dispose();
PropertyTree = null;
@ -122,78 +112,30 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private void PopulateProperties(ProfileElement profileElement)
{
if (_lastSelectedLayer != null)
{
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
}
LayerPropertyGroups.Clear();
if (profileElement is Layer layer)
{
// Create VMs for missing properties
foreach (var baseLayerProperty in layer.Properties)
// Add the built-in root groups of the layer
var generalAttribute = Attribute.GetCustomAttribute(
layer.GetType().GetProperty(nameof(layer.General)),
typeof(PropertyGroupDescriptionAttribute)
);
var transformAttribute = Attribute.GetCustomAttribute(
layer.GetType().GetProperty(nameof(layer.Transform)),
typeof(PropertyGroupDescriptionAttribute)
);
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
// Add the rout group of the brush
// The root group of the brush has no attribute so let's pull one out of our sleeve
var brushDescription = new PropertyGroupDescriptionAttribute
{
if (_layerPropertyViewModels.All(vm => vm.LayerProperty != baseLayerProperty))
CreatePropertyViewModel(baseLayerProperty);
}
// Remove VMs for extra properties
foreach (var layerPropertyViewModel in _layerPropertyViewModels.ToList())
{
if (layer.Properties.All(p => p != layerPropertyViewModel.LayerProperty))
RemovePropertyViewModel(layerPropertyViewModel);
}
_lastSelectedLayer = layer;
layer.Properties.LayerPropertyRegistered += LayerOnPropertyRegistered;
layer.Properties.LayerPropertyRemoved += LayerOnPropertyRemoved;
Name = layer.LayerBrush.Descriptor.DisplayName,
Description = layer.LayerBrush.Descriptor.Description
};
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.LayerBrush.BaseProperties, brushDescription));
}
else
{
foreach (var layerPropertyViewModel in _layerPropertyViewModels.ToList())
RemovePropertyViewModel(layerPropertyViewModel);
_lastSelectedLayer = null;
}
}
private void LayerOnPropertyRegistered(object sender, LayerPropertyEventArgs e)
{
Console.WriteLine("LayerOnPropertyRegistered");
PopulateProperties(e.LayerProperty.Layer);
}
private void LayerOnPropertyRemoved(object sender, LayerPropertyEventArgs e)
{
Console.WriteLine("LayerOnPropertyRemoved");
PopulateProperties(e.LayerProperty.Layer);
}
private LayerPropertyViewModel CreatePropertyViewModel(BaseLayerProperty layerProperty)
{
LayerPropertyViewModel parent = null;
// If the property has a parent, find it's VM
if (layerProperty.Parent != null)
{
parent = _layerPropertyViewModels.FirstOrDefault(vm => vm.LayerProperty == layerProperty.Parent);
// If no VM is found, create it
if (parent == null)
parent = CreatePropertyViewModel(layerProperty.Parent);
}
var createdViewModel = _layerPropertyVmFactory.Create(layerProperty, parent);
_layerPropertyViewModels.Add(createdViewModel);
PropertyTree.AddLayerProperty(createdViewModel);
PropertyTimeline.AddLayerProperty(createdViewModel);
return createdViewModel;
}
private void RemovePropertyViewModel(LayerPropertyViewModel layerPropertyViewModel)
{
PropertyTree.RemoveLayerProperty(layerPropertyViewModel);
PropertyTimeline.RemoveLayerProperty(layerPropertyViewModel);
_layerPropertyViewModels.Remove(layerPropertyViewModel);
}
#endregion
@ -259,9 +201,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private TimeSpan CalculateEndTime()
{
// End time is the last keyframe + 10 sec
var lastKeyFrame = PropertyTimeline.PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault();
return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.MaxValue;
if (!(_profileEditorService.SelectedProfileElement is Layer layer))
return TimeSpan.MaxValue;
var keyframes = GetKeyframes(false);
// If there are no keyframes, don't stop at all
if (!keyframes.Any())
return TimeSpan.MaxValue;
// If there are keyframes, stop after the last keyframe + 10 sec
return keyframes.Max(k => k.Position).Add(TimeSpan.FromSeconds(10));
}
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
@ -323,19 +272,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
return;
}
// If shift is held, snap to closest keyframe
var visibleKeyframes = PropertyTimeline.PropertyTrackViewModels
.Where(t => t.LayerPropertyViewModel.Parent != null && t.LayerPropertyViewModel.Parent.IsExpanded)
.SelectMany(t => t.KeyframeViewModels);
var visibleKeyframes = GetKeyframes(true);
// Take a tolerance of 5 pixels (half a keyframe width)
var tolerance = 1000f / PixelsPerSecond * 5;
var closeKeyframe = visibleKeyframes.FirstOrDefault(
kf => Math.Abs(kf.Keyframe.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance
);
_profileEditorService.CurrentTime = closeKeyframe?.Keyframe.Position ?? newTime;
var closeKeyframe = visibleKeyframes.FirstOrDefault(k => Math.Abs(k.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance);
_profileEditorService.CurrentTime = closeKeyframe?.Position ?? newTime;
}
}
private List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{
var result = new List<BaseLayerPropertyKeyframe>();
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
result.AddRange(layerPropertyGroupViewModel.GetKeyframes(visibleOnly));
return result;
}
#endregion
#region Events

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertyGroupViewModel : LayerPropertyBaseViewModel
{
public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription)
{
LayerPropertyGroup = layerPropertyGroup;
PropertyGroupDescription = propertyGroupDescription;
IsExpanded = PropertyGroupDescription.ExpandByDefault;
Children = new List<LayerPropertyBaseViewModel>();
PopulateChildren();
}
public LayerPropertyGroup LayerPropertyGroup { get; }
public PropertyGroupDescriptionAttribute PropertyGroupDescription { get; }
public bool IsExpanded { get; set; }
public List<LayerPropertyBaseViewModel> Children { get; set; }
private void PopulateChildren()
{
// Get all properties and property groups and create VMs for them
foreach (var propertyInfo in LayerPropertyGroup.GetType().GetProperties())
{
var propertyAttribute = (PropertyDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyDescriptionAttribute));
var groupAttribute = (PropertyGroupDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyGroupDescriptionAttribute));
var value = propertyInfo.GetValue(LayerPropertyGroup);
// Create VMs for properties on the group
if (propertyAttribute != null && value is BaseLayerProperty)
{
// Go through the pain of instantiating a generic type VM now via reflection to make things a lot simpler down the line
var genericType = propertyInfo.PropertyType.GetGenericArguments()[0];
var genericViewModel = typeof(LayerPropertyViewModel<>).MakeGenericType(genericType);
var instance = Activator.CreateInstance(genericViewModel, value, propertyAttribute);
Children.Add((LayerPropertyBaseViewModel) instance);
}
// Create VMs for child groups on this group, resulting in a nested structure
else if (groupAttribute != null && value is LayerPropertyGroup layerPropertyGroup)
{
Children.Add(new LayerPropertyGroupViewModel(layerPropertyGroup, groupAttribute));
}
}
}
public override List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{
var result = new List<BaseLayerPropertyKeyframe>();
if (!IsExpanded)
return result;
foreach (var layerPropertyBaseViewModel in Children)
result.AddRange(layerPropertyBaseViewModel.GetKeyframes(visibleOnly));
return result;
}
}
}

View File

@ -1,108 +1,25 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Utilities;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput;
using Artemis.UI.Services.Interfaces;
using Ninject;
using Stylet;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertyViewModel<T> : LayerPropertyViewModel
public class LayerPropertyViewModel<T> : LayerPropertyBaseViewModel
{
private readonly IKernel _kernel;
private readonly IProfileEditorService _profileEditorService;
private bool _keyframesEnabled;
private bool _isExpanded;
public LayerPropertyViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel parent, IKernel kernel, IProfileEditorService profileEditorService)
public LayerPropertyViewModel(LayerProperty<T> layerProperty, PropertyDescriptionAttribute propertyDescription)
{
_kernel = kernel;
_profileEditorService = profileEditorService;
_keyframesEnabled = layerProperty.KeyframesEnabled;
LayerProperty = layerProperty;
Parent = parent;
Children = new List<LayerPropertyViewModel>();
// TODO: Get from attribute
IsExpanded = false;
Parent?.Children.Add(this);
PropertyDescription = propertyDescription;
}
public LayerProperty<T> LayerProperty { get; }
public PropertyDescriptionAttribute PropertyDescription { get; }
public bool IsExpanded
public override List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{
get => _isExpanded;
set
{
_isExpanded = value;
OnExpandedStateChanged();
}
return LayerProperty.BaseKeyframes.ToList();
}
public bool KeyframesEnabled
{
get => _keyframesEnabled;
set
{
_keyframesEnabled = value;
UpdateKeyframes();
}
}
public PropertyInputViewModel GetPropertyInputViewModel()
{
// If the type is an enum type, search for Enum instead.
var type = typeof(T);
if (type.IsEnum)
type = typeof(Enum);
var match = _kernel.Get<List<PropertyInputViewModel>>().FirstOrDefault(p => p.CompatibleTypes.Contains(type));
if (match == null)
return null;
match.Initialize(this);
return match;
}
private void UpdateKeyframes()
{
// Either create a new first keyframe or clear all the keyframes
if (_keyframesEnabled)
LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(LayerProperty.CurrentValue, _profileEditorService.CurrentTime, Easings.Functions.Linear));
else
LayerProperty.ClearKeyframes();
// Force the keyframe engine to update, the new keyframe is the current keyframe
LayerProperty.KeyframesEnabled = _keyframesEnabled;
LayerProperty.Update(0);
_profileEditorService.UpdateSelectedProfileElement();
}
#region Events
public event EventHandler<EventArgs> ExpandedStateChanged;
protected virtual void OnExpandedStateChanged()
{
ExpandedStateChanged?.Invoke(this, EventArgs.Empty);
foreach (var layerPropertyViewModel in Children)
layerPropertyViewModel.OnExpandedStateChanged();
}
#endregion
}
public class LayerPropertyViewModel : PropertyChangedBase
{
public LayerPropertyViewModel Parent { get; protected set; }
public List<LayerPropertyViewModel> Children { get; protected set; }
}
}