diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index 0bb00863f..f28a911f5 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -17,7 +17,6 @@ namespace Artemis.Core private readonly List _modifiers = new List(); private object _currentValue; - private bool _isInitialized; private object _previousValue; private TimeSpan _easingProgress; @@ -200,6 +199,9 @@ namespace Artemis.Core /// The time in seconds that passed since the last update public void Update(double deltaTime) { + // Data bindings cannot go back in time like brushes + deltaTime = Math.Max(0, deltaTime); + _easingProgress = _easingProgress.Add(TimeSpan.FromSeconds(deltaTime)); if (_easingProgress > EasingTime) _easingProgress = EasingTime; @@ -256,11 +258,8 @@ namespace Artemis.Core internal void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService) { - if (_isInitialized) - throw new ArtemisCoreException("Data binding is already initialized"); - // Source - if (Entity.SourceDataModelGuid != null) + if (Entity.SourceDataModelGuid != null && SourceDataModel == null) { var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.SourceDataModelGuid.Value); if (dataModel != null && dataModel.ContainsPath(Entity.SourcePropertyPath)) @@ -270,8 +269,6 @@ namespace Artemis.Core // Modifiers foreach (var dataBindingModifier in Modifiers) dataBindingModifier.Initialize(dataModelService, dataBindingService); - - _isInitialized = true; } private void ApplyRegistration(DataBindingRegistration dataBindingRegistration) diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs index 6eac1806d..163c35ac4 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs @@ -4,8 +4,6 @@ using System.Linq.Expressions; using Artemis.Core.DataModelExpansions; using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.DataBindings; -using LiteDB.Engine; -using Microsoft.VisualBasic; using Newtonsoft.Json; namespace Artemis.Core @@ -16,10 +14,9 @@ namespace Artemis.Core public class DataBindingModifier { private DataBinding _dataBinding; - private bool _isInitialized; /// - /// Creates a new instance of the class + /// Creates a new instance of the class /// /// The type of the parameter, can either be dynamic (based on a data model value) or static public DataBindingModifier(ProfileRightSideType parameterType) @@ -83,7 +80,7 @@ namespace Artemis.Core public object ParameterStaticValue { get; private set; } /// - /// A compiled expression tree that when given a matching data model returns the value of the modifiers parameter + /// A compiled expression tree that when given a matching data model returns the value of the modifiers parameter /// public Func CompiledParameterAccessor { get; set; } @@ -96,13 +93,19 @@ namespace Artemis.Core /// The modified value public object Apply(object currentValue) { + if (ModifierType == null) + return currentValue; + + if (!ModifierType.SupportsParameter) + return ModifierType.Apply(currentValue, null); + if (ParameterType == ProfileRightSideType.Dynamic && CompiledParameterAccessor != null) { var value = CompiledParameterAccessor(ParameterDataModel); return ModifierType.Apply(currentValue, value); } - if (ParameterType == ProfileRightSideType.Static && ModifierType != null) + if (ParameterType == ProfileRightSideType.Static) return ModifierType.Apply(currentValue, ParameterStaticValue); return currentValue; @@ -186,11 +189,8 @@ namespace Artemis.Core internal void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService) { - if (_isInitialized) - throw new ArtemisCoreException("Data binding modifier is already initialized"); - // Modifier type - if (Entity.ModifierTypePluginGuid != null) + if (Entity.ModifierTypePluginGuid != null && ModifierType == null) { var modifierType = dataBindingService.GetModifierType(Entity.ModifierTypePluginGuid.Value, Entity.ModifierType); if (modifierType != null) @@ -198,14 +198,14 @@ namespace Artemis.Core } // Dynamic parameter - if (ParameterType == ProfileRightSideType.Dynamic && Entity.ParameterDataModelGuid != null) + if (ParameterType == ProfileRightSideType.Dynamic && Entity.ParameterDataModelGuid != null && ParameterDataModel == null) { var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.ParameterDataModelGuid.Value); if (dataModel != null && dataModel.ContainsPath(Entity.ParameterPropertyPath)) UpdateParameter(dataModel, Entity.ParameterPropertyPath); } // Static parameter - else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null) + else if (ParameterType == ProfileRightSideType.Static && Entity.ParameterStaticValue != null && ParameterStaticValue == null) { // Use the target type so JSON.NET has a better idea what to do var targetType = DataBinding.TargetProperty.PropertyType; @@ -224,41 +224,6 @@ namespace Artemis.Core UpdateParameter(staticValue); } - - _isInitialized = true; - } - - - private void CreateExpression() - { - CompiledParameterAccessor = null; - - if (ModifierType == null || DataBinding == null) - return; - - if (ParameterType == ProfileRightSideType.Dynamic && ModifierType.SupportsParameter) - { - if (ParameterDataModel == null) - return; - - // If the right side value is null, the constant type cannot be inferred and must be provided based on the data binding target - var parameterAccessor = CreateAccessor(ParameterDataModel, ParameterPropertyPath, "parameter", out var rightSideParameter); - var lambda = Expression.Lambda>(Expression.Convert(parameterAccessor, typeof(object)), rightSideParameter); - CompiledParameterAccessor = lambda.Compile(); - } - } - - private Expression CreateAccessor(DataModel dataModel, string path, string parameterName, out ParameterExpression parameter) - { - var listType = dataModel.GetListTypeInPath(path); - if (listType != null) - throw new ArtemisCoreException($"Cannot create a regular accessor at path {path} because the path contains a list"); - - parameter = Expression.Parameter(typeof(object), parameterName + "DataModel"); - return path.Split('.').Aggregate( - Expression.Convert(parameter, dataModel.GetType()), // Cast to the appropriate type - Expression.Property - ); } internal void ApplyToEntity() @@ -287,5 +252,38 @@ namespace Artemis.Core // Parameter is done during initialize } + + + private void CreateExpression() + { + CompiledParameterAccessor = null; + + if (ModifierType == null || DataBinding == null) + return; + + if (ParameterType == ProfileRightSideType.Dynamic && ModifierType.SupportsParameter) + { + if (ParameterDataModel == null) + return; + + // If the right side value is null, the constant type cannot be inferred and must be provided based on the data binding target + var parameterAccessor = CreateAccessor(ParameterDataModel, ParameterPropertyPath, "parameter", out var rightSideParameter); + var lambda = Expression.Lambda>(Expression.Convert(parameterAccessor, typeof(object)), rightSideParameter); + CompiledParameterAccessor = lambda.Compile(); + } + } + + private Expression CreateAccessor(DataModel dataModel, string path, string parameterName, out ParameterExpression parameter) + { + var listType = dataModel.GetListTypeInPath(path); + if (listType != null) + throw new ArtemisCoreException($"Cannot create a regular accessor at path {path} because the path contains a list"); + + parameter = Expression.Parameter(typeof(object), parameterName + "DataModel"); + return path.Split('.').Aggregate( + Expression.Convert(parameter, dataModel.GetType()), // Cast to the appropriate type + Expression.Property + ); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/FloorModifierType.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/FloorModifierType.cs new file mode 100644 index 000000000..d04f4cf6a --- /dev/null +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/FloorModifierType.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Artemis.Core +{ + internal class FloorModifierType : DataBindingModifierType + { + public FloorModifierType() + { + SupportsParameter = false; + } + + public override IReadOnlyCollection CompatibleTypes => Constants.NumberTypes; + public override string Description => "Floor"; + public override string Icon => "ArrowDownDropCircleOutline"; + + + public override object Apply(object currentValue, object parameterValue) + { + var floatValue = Convert.ToSingle(currentValue); + return Math.Floor(floatValue); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index d4a762a64..ec44b97d3 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -39,6 +39,7 @@ namespace Artemis.Core return; base.BaseValue = value; + Update(); OnBaseValueChanged(); } } @@ -104,7 +105,7 @@ namespace Artemis.Core // Force an update so that the base value is applied to the current value and // keyframes/data bindings are applied using the new base value - Update(0); + Update(); } /// @@ -195,7 +196,7 @@ namespace Artemis.Core /// /// Updates the property, applying keyframes and data bindings to the current value /// - internal void Update(double deltaTime) + internal void Update(double deltaTime = 0) { CurrentValue = BaseValue; diff --git a/src/Artemis.Core/Services/DataBindingService.cs b/src/Artemis.Core/Services/DataBindingService.cs index 4a215c211..199408fa2 100644 --- a/src/Artemis.Core/Services/DataBindingService.cs +++ b/src/Artemis.Core/Services/DataBindingService.cs @@ -104,6 +104,8 @@ namespace Artemis.Core.Services private void RegisterBuiltInModifiers() { RegisterModifierType(Constants.CorePluginInfo, new MultiplicationModifierType()); + RegisterModifierType(Constants.CorePluginInfo, new DivideModifierType()); + RegisterModifierType(Constants.CorePluginInfo, new FloorModifierType()); } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index 5c2395661..ac437396b 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -111,6 +111,8 @@ namespace Artemis.UI.Shared.Services var profileElementEvent = new RenderProfileElementEventArgs(profileElement, SelectedProfileElement); SelectedProfileElement = profileElement; OnSelectedProfileElementChanged(profileElementEvent); + + ChangeSelectedDataBinding(null); } } diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingModifierViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingModifierViewModel.cs index af6bf2689..58849824e 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingModifierViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingModifierViewModel.cs @@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings SelectModifierTypeCommand = new DelegateCommand(ExecuteSelectModifierTypeCommand); // Initialize async, no need to wait for it - Execute.PostToUIThread(Initialize); + Execute.PostToUIThread(Update); } public DelegateCommand SelectModifierTypeCommand { get; } @@ -62,30 +62,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings get => _staticInputViewModel; private set => SetAndNotify(ref _staticInputViewModel, value); } - - private void Initialize() - { - var sourceType = Modifier.DataBinding.GetSourceType(); - if (sourceType == null) - throw new ArtemisUIException("Cannot initialize a data binding modifier VM for a data binding without a source"); - - if (Modifier.ParameterType == ProfileRightSideType.Dynamic) - { - StaticInputViewModel = null; - DynamicSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); - DynamicSelectionViewModel.PropertySelected += ParameterSelectionViewModelOnPropertySelected; - DynamicSelectionViewModel.FilterTypes = new[] {sourceType}; - } - else - { - DynamicSelectionViewModel = null; - StaticInputViewModel = _dataModelUIService.GetStaticInputViewModel(sourceType); - StaticInputViewModel.ValueUpdated += StaticInputViewModelOnValueUpdated; - } - - Update(); - } - + private void ParameterSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) { Modifier.UpdateParameter(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.PropertyPath); @@ -99,6 +76,27 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings private void Update() { var sourceType = Modifier.DataBinding.GetSourceType(); + if (sourceType == null) + throw new ArtemisUIException("Cannot use a data binding modifier VM for a data binding without a source"); + + if (Modifier.ModifierType == null || !Modifier.ModifierType.SupportsParameter) + { + StaticInputViewModel = null; + DynamicSelectionViewModel = null; + } + else if (Modifier.ParameterType == ProfileRightSideType.Dynamic) + { + StaticInputViewModel = null; + DynamicSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); + DynamicSelectionViewModel.PropertySelected += ParameterSelectionViewModelOnPropertySelected; + DynamicSelectionViewModel.FilterTypes = new[] { sourceType }; + } + else + { + DynamicSelectionViewModel = null; + StaticInputViewModel = _dataModelUIService.GetStaticInputViewModel(sourceType); + StaticInputViewModel.ValueUpdated += StaticInputViewModelOnValueUpdated; + } // Modifier type ModifierTypes.Clear(); @@ -135,7 +133,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings else Modifier.UpdateParameter(null, null); - Initialize(); + Update(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs index f5d110c1e..6397b9437 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using System.Timers; using Artemis.Core; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline; @@ -11,21 +10,20 @@ using Stylet; namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings { - public class DataBindingViewModel : PropertyChangedBase + public class DataBindingViewModel : PropertyChangedBase, IDisposable { private readonly IDataBindingsVmFactory _dataBindingsVmFactory; private readonly IDataModelUIService _dataModelUIService; private readonly IProfileEditorService _profileEditorService; - private readonly Timer _updateTimer; private DataBinding _dataBinding; + private int _easingTime; private bool _isDataBindingEnabled; + private bool _isEasingTimeEnabled; + private DataBindingMode _selectedDataBindingMode; + private TimelineEasingViewModel _selectedEasingViewModel; private DataModelDynamicViewModel _targetSelectionViewModel; private object _testInputValue; private object _testResultValue; - private TimelineEasingViewModel _selectedEasingViewModel; - private DataBindingMode _selectedDataBindingMode; - private int _easingTime; - private bool _isEasingTimeEnabled; private bool _updating; public DataBindingViewModel(DataBindingRegistration registration, @@ -37,7 +35,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings _profileEditorService = profileEditorService; _dataModelUIService = dataModelUIService; _dataBindingsVmFactory = dataBindingsVmFactory; - _updateTimer = new Timer(500); DisplayName = Registration.Property.Name.ToUpper(); @@ -181,18 +178,16 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast().Select(v => new TimelineEasingViewModel(null, v))); TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected; + _profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated; Update(); - - _updateTimer.Start(); - _updateTimer.Elapsed += OnUpdateTimerOnElapsed; } private void Update() { if (_updating) return; - + if (DataBinding == null) { TargetSelectionViewModel.IsEnabled = false; @@ -201,7 +196,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings } _updating = true; - + SelectedDataBindingMode = DataBinding.Mode; EasingTime = (int) DataBinding.EasingTime.TotalMilliseconds; SelectedEasingViewModel = EasingViewModels.First(vm => vm.EasingFunction == DataBinding.EasingFunction); @@ -229,22 +224,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings Update(); } - private void DataBindingOnModifiersUpdated(object sender, EventArgs e) - { - UpdateModifierViewModels(); - } - - private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) - { - DataBinding.UpdateSource(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.PropertyPath); - _profileEditorService.UpdateSelectedProfileElement(); - } - - private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e) - { - UpdateTestResult(); - } - private void UpdateTestResult() { var currentValue = TargetSelectionViewModel.SelectedPropertyViewModel?.GetCurrentValue(); @@ -264,5 +243,29 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings foreach (var dataBindingModifier in DataBinding.Modifiers) ModifierViewModels.Add(_dataBindingsVmFactory.DataBindingModifierViewModel(dataBindingModifier)); } + + private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e) + { + UpdateTestResult(); + } + + private void DataBindingOnModifiersUpdated(object sender, EventArgs e) + { + UpdateModifierViewModels(); + } + + private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) + { + DataBinding.UpdateSource(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.PropertyPath); + _profileEditorService.UpdateSelectedProfileElement(); + } + + public void Dispose() + { + _profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated; + TargetSelectionViewModel.PropertySelected -= TargetSelectionViewModelOnPropertySelected; + if (DataBinding != null) + DataBinding.ModifiersUpdated -= DataBindingOnModifiersUpdated; + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingsViewModel.cs index 85680795b..585abf21f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingsViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingsViewModel.cs @@ -1,11 +1,12 @@ -using System.Linq; +using System; +using System.Linq; using Artemis.Core; using Artemis.UI.Ninject.Factories; using Stylet; namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings { - public class DataBindingsViewModel : PropertyChangedBase + public class DataBindingsViewModel : PropertyChangedBase, IDisposable { private readonly IDataBindingsVmFactory _dataBindingsVmFactory; private DataBindingsTabsViewModel _dataBindingsTabsViewModel; @@ -34,6 +35,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings private void Initialise() { + DataBindingViewModel?.Dispose(); DataBindingViewModel = null; DataBindingsTabsViewModel = null; @@ -52,5 +54,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings DataBindingsTabsViewModel.Tabs.Add(_dataBindingsVmFactory.DataBindingViewModel(registration)); } } + + public void Dispose() + { + DataBindingViewModel?.Dispose(); + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index a2f45e84f..4aebe4602 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -204,6 +204,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties MainTimelineSegmentViewModel = null; EndTimelineSegmentViewModel?.Dispose(); EndTimelineSegmentViewModel = null; + DataBindingsViewModel?.Dispose(); + DataBindingsViewModel = null; base.OnClose(); } @@ -241,6 +243,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties if (ProfileEditorService.SelectedDataBinding != null) { RightSideIndex = 1; + DataBindingsViewModel?.Dispose(); DataBindingsViewModel = _dataBindingsVmFactory.DataBindingsViewModel(ProfileEditorService.SelectedDataBinding); } else diff --git a/src/Plugins/Artemis.Plugins.Modules.General/DataModels/GeneralDataModel.cs b/src/Plugins/Artemis.Plugins.Modules.General/DataModels/GeneralDataModel.cs index 030909ace..da72828a4 100644 --- a/src/Plugins/Artemis.Plugins.Modules.General/DataModels/GeneralDataModel.cs +++ b/src/Plugins/Artemis.Plugins.Modules.General/DataModels/GeneralDataModel.cs @@ -29,7 +29,6 @@ namespace Artemis.Plugins.Modules.General.DataModels public class TimeDataModel : DataModel { public DateTimeOffset CurrentTime { get; set; } - public long SecondsSinceUnixEpoch { get; set; } public TimeSpan TimeSinceMidnight { get; set; } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs index ba21a0597..e6bfecda7 100644 --- a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -41,7 +41,6 @@ namespace Artemis.Plugins.Modules.General public override void Update(double deltaTime) { DataModel.TimeDataModel.CurrentTime = DateTimeOffset.Now; - DataModel.TimeDataModel.SecondsSinceUnixEpoch = DateTimeOffset.Now.ToUnixTimeSeconds(); DataModel.TimeDataModel.TimeSinceMidnight = DateTimeOffset.Now - DateTimeOffset.Now.Date; UpdateCurrentWindow(); }