From 34d11d8a1f1b77b05748647cab9556a32117def0 Mon Sep 17 00:00:00 2001
From: denglihong2007 <98096191+denglihong2007@users.noreply.github.com>
Date: Fri, 1 Aug 2025 10:48:06 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=97=B6=E9=97=B4=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CRSim.Core/Abstractions/ITimeService.cs | 12 ++--
CRSim.Core/Models/Settings.cs | 2 -
CRSim.Core/Services/SettingsService.cs | 2 -
CRSim.Core/Services/TimeService.cs | 64 ++++++++++++++-----
CRSim.ScreenSimulator/StyleManager.cs | 9 ++-
.../MetroPlatformScreenViewModel.cs | 10 +--
.../ViewModels/ScreenViewModel.cs | 18 +++---
CRSim/App.xaml.cs | 5 +-
.../ScreenSimulatorPageViewModel.cs | 9 ++-
CRSim/ViewModels/SettingsPageViewModel.cs | 5 --
CRSim/Views/ScreenSimulatorPage.xaml | 8 ++-
CRSim/Views/SettingsPage.xaml | 3 -
12 files changed, 91 insertions(+), 56 deletions(-)
diff --git a/CRSim.Core/Abstractions/ITimeService.cs b/CRSim.Core/Abstractions/ITimeService.cs
index 3889ef7..293e8b6 100644
--- a/CRSim.Core/Abstractions/ITimeService.cs
+++ b/CRSim.Core/Abstractions/ITimeService.cs
@@ -1,16 +1,16 @@
-using System;
-using System.Timers;
-
-namespace CRSim.Core.Abstractions
+namespace CRSim.Core.Abstractions
{
public interface ITimeService
{
- event EventHandler OneSecondElapsed; // 1秒触发的事件
- event EventHandler RefreshSecondsElapsed; // 20秒触发的事件
+ event EventHandler OneSecondElapsed;
+ event EventHandler RefreshSecondsElapsed;
void Start();
void Stop();
DateTime GetDateTimeNow();
+
+ DateTime SimulateTime { get; set; } // 初始模拟时间
+ double Speed { get; set; } // 模拟倍速
}
}
\ No newline at end of file
diff --git a/CRSim.Core/Models/Settings.cs b/CRSim.Core/Models/Settings.cs
index 0af445a..4b4b8ef 100644
--- a/CRSim.Core/Models/Settings.cs
+++ b/CRSim.Core/Models/Settings.cs
@@ -5,8 +5,6 @@ namespace CRSim.Core.Models
{
public class Settings
{
- public TimeSpan TimeOffset { get; set; } = TimeSpan.Zero;
-
public TimeSpan DepartureCheckInAdvanceDuration { get; set; } = TimeSpan.FromMinutes(20);
public TimeSpan PassingCheckInAdvanceDuration { get; set; } = TimeSpan.FromMinutes(10);
diff --git a/CRSim.Core/Services/SettingsService.cs b/CRSim.Core/Services/SettingsService.cs
index 29b00d0..7bc6022 100644
--- a/CRSim.Core/Services/SettingsService.cs
+++ b/CRSim.Core/Services/SettingsService.cs
@@ -15,7 +15,6 @@ namespace CRSim.Core.Services
}
public void SaveSettings()
{
- _key.SetValue("TimeOffset", (int)_settings.TimeOffset.TotalMinutes);
_key.SetValue("SwitchPageSeconds", _settings.SwitchPageSeconds);
_key.SetValue("ApiUri", _settings.ApiUri);
_key.SetValue("MaxPages", _settings.MaxPages);
@@ -40,7 +39,6 @@ namespace CRSim.Core.Services
else
{
_settings = new Settings();
- if (_key.GetValue("TimeOffset") != null) _settings.TimeOffset = TimeSpan.FromMinutes((int)_key.GetValue("TimeOffset"));
if (_key.GetValue("SwitchPageSeconds") != null) _settings.SwitchPageSeconds = (int)_key.GetValue("SwitchPageSeconds");
if (_key.GetValue("ApiUri") != null) _settings.ApiUri = (string)_key.GetValue("ApiUri");
if (_key.GetValue("MaxPages") != null) _settings.MaxPages = (int)_key.GetValue("MaxPages");
diff --git a/CRSim.Core/Services/TimeService.cs b/CRSim.Core/Services/TimeService.cs
index e802530..a36baab 100644
--- a/CRSim.Core/Services/TimeService.cs
+++ b/CRSim.Core/Services/TimeService.cs
@@ -1,5 +1,4 @@
-
-using CRSim.Core.Abstractions;
+using CRSim.Core.Abstractions;
using CRSim.Core.Models;
using System.Timers;
@@ -7,49 +6,82 @@ namespace CRSim.Core.Services
{
public class TimeService : ITimeService
{
- private readonly Settings _settings;
- private readonly System.Timers.Timer _oneSecondTimer;
- private readonly System.Timers.Timer _twentySecondsTimer;
+ public DateTime SimulateTime { get; set; }
- public event EventHandler OneSecondElapsed;
- public event EventHandler RefreshSecondsElapsed;
+ private double _speed = 1.0;
+ public double Speed
+ {
+ get => _speed;
+ set
+ {
+ UpdateSimulatedOffset(); // 切换前先结算旧速率下的时间
+ _speed = value;
+ _lastSpeedChangeTime = DateTime.Now;
+ }
+ }
+
+ private DateTime _lastSpeedChangeTime; // 上一次倍速切换时的真实时间
+ private TimeSpan _simulatedOffset = TimeSpan.Zero; // 累计模拟时间偏移(倍速放大之后的)
+
+ private readonly System.Timers.Timer _oneSecondTimer;
+ private readonly System.Timers.Timer _twentySecondsTimer;
+
+ public event EventHandler OneSecondElapsed;
+ public event EventHandler RefreshSecondsElapsed;
+
+ private Settings _settings;
public TimeService(ISettingsService settingsService)
{
_settings = settingsService.GetSettings();
- _oneSecondTimer = new(1000);
+ _oneSecondTimer = new(1000);
_oneSecondTimer.Elapsed += OnOneSecondElapsed;
- _twentySecondsTimer = new(_settings.SwitchPageSeconds*1000);
+ _twentySecondsTimer = new(_settings.SwitchPageSeconds * 1000);
_twentySecondsTimer.Elapsed += OnTwentySecondsElapsed;
+
+ _lastSpeedChangeTime = DateTime.Now;
}
public void Start()
{
- _oneSecondTimer.Start();
- _twentySecondsTimer.Start();
+ _oneSecondTimer.Start();
+ _twentySecondsTimer.Start();
+ _lastSpeedChangeTime = DateTime.Now; // 启动时刷新时间
}
public void Stop()
{
- _oneSecondTimer.Stop();
- _twentySecondsTimer.Stop();
+ _oneSecondTimer.Stop();
+ _twentySecondsTimer.Stop();
}
private void OnOneSecondElapsed(object sender, ElapsedEventArgs e)
{
- OneSecondElapsed?.Invoke(this, EventArgs.Empty);
+ OneSecondElapsed?.Invoke(this, EventArgs.Empty);
}
private void OnTwentySecondsElapsed(object sender, ElapsedEventArgs e)
{
- RefreshSecondsElapsed?.Invoke(this, EventArgs.Empty);
+ RefreshSecondsElapsed?.Invoke(this, EventArgs.Empty);
}
public DateTime GetDateTimeNow()
{
- return DateTime.Now+ _settings.TimeOffset;
+ var now = DateTime.Now;
+ var elapsed = now - _lastSpeedChangeTime;
+ return SimulateTime + _simulatedOffset + TimeSpan.FromTicks((long)(elapsed.Ticks * Speed));
+ }
+
+ ///
+ /// 当倍速改变时,先结算之前段的累计偏移
+ ///
+ private void UpdateSimulatedOffset()
+ {
+ var now = DateTime.Now;
+ var elapsed = now - _lastSpeedChangeTime;
+ _simulatedOffset += TimeSpan.FromTicks((long)(elapsed.Ticks * Speed));
}
}
}
\ No newline at end of file
diff --git a/CRSim.ScreenSimulator/StyleManager.cs b/CRSim.ScreenSimulator/StyleManager.cs
index 710aea7..867bcff 100644
--- a/CRSim.ScreenSimulator/StyleManager.cs
+++ b/CRSim.ScreenSimulator/StyleManager.cs
@@ -12,17 +12,22 @@ namespace CRSim.ScreenSimulator
public static List StyleInfos => [.. IPluginService.LoadedPlugins.Where(x => x.Manifest.Type == "ScreenStyle" && x.LoadStatus == PluginLoadStatus.Loaded)];
public static IServiceProvider ServiceProvider;
private static IDatabaseService _databaseService;
- public StyleManager(IEnumerable pluginBases,IServiceProvider serviceProvider,IDatabaseService databaseService)
+ public StyleManager(IServiceProvider serviceProvider,IDatabaseService databaseService)
{
ServiceProvider = serviceProvider;
_databaseService = databaseService;
}
- public static void ShowWindow(Type page, Station station, string ticketCheck, string platform,string text,int location,string video)
+ public static void ShowWindow(Type page, Station station, string ticketCheck, string platform,string? text,int location,string? video,DateTime dateTime)
{
Thread thread = new(() =>
{
Page viewInstance = (Page)ServiceProvider.GetService(page);
var viewModel = ((dynamic)viewInstance).ViewModel;
+
+ var timeService = ((ITimeService)viewModel.TimeService);
+ timeService.SimulateTime = dateTime;
+ timeService.Start();
+
viewModel.UIDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
if (text != null)
{
diff --git a/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs b/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
index 52556db..1f4d7ef 100644
--- a/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
+++ b/CRSim.ScreenSimulator/ViewModels/MetroPlatformScreenViewModel.cs
@@ -7,7 +7,7 @@ namespace CRSim.ScreenSimulator.ViewModels
{
public partial class MetroPlatformScreenViewModel : ObservableObject
{
- public readonly ITimeService _timeService;
+ public readonly ITimeService TimeService;
public readonly Settings _settings;
[ObservableProperty]
private DateTime _currentTime = new();
@@ -23,14 +23,14 @@ namespace CRSim.ScreenSimulator.ViewModels
public List TrainInfos { get; set; } = [];
public MetroPlatformScreenViewModel(ITimeService timeService, ISettingsService settingsService)
{
- _timeService = timeService;
+ TimeService = timeService;
_settings = settingsService.GetSettings();
timeService.OneSecondElapsed += RefreshDisplay;
}
private void RefreshDisplay(object? sender, EventArgs e)
{
- CurrentTime = _timeService.GetDateTimeNow();
- List itemsToRemove = [.. TrainInfos.Where(info => info.DepartureTime < _timeService.GetDateTimeNow())];
+ CurrentTime = TimeService.GetDateTimeNow();
+ List itemsToRemove = [.. TrainInfos.Where(info => info.DepartureTime < TimeService.GetDateTimeNow())];
foreach (var item in itemsToRemove)
{
TrainInfos.Remove(item);
@@ -48,7 +48,7 @@ namespace CRSim.ScreenSimulator.ViewModels
{
if (trainNumber != null && trainNumber.DepartureTime != null && trainNumber.Platform == platform)
{
- var now = _timeService.GetDateTimeNow();
+ var now = TimeService.GetDateTimeNow();
var today = now.Date;
if (_settings.LoadTodayOnly && today.Add((trainNumber.DepartureTime ?? trainNumber.ArrivalTime)!.Value) < now)
{
diff --git a/CRSim.ScreenSimulator/ViewModels/ScreenViewModel.cs b/CRSim.ScreenSimulator/ViewModels/ScreenViewModel.cs
index b289172..d6a3d38 100644
--- a/CRSim.ScreenSimulator/ViewModels/ScreenViewModel.cs
+++ b/CRSim.ScreenSimulator/ViewModels/ScreenViewModel.cs
@@ -9,7 +9,7 @@ namespace CRSim.ScreenSimulator.ViewModels
{
public partial class BaseScreenViewModel : ObservableObject
{
- public readonly ITimeService _timeService;
+ public readonly ITimeService TimeService;
public readonly Settings _settings;
public readonly TaskCompletionSource DataLoaded = new();
[ObservableProperty]
@@ -35,13 +35,13 @@ namespace CRSim.ScreenSimulator.ViewModels
protected BaseScreenViewModel(ITimeService timeService, ISettingsService settingsService)
{
- _timeService = timeService;
+ TimeService = timeService;
_settings = settingsService.GetSettings();
- _timeService.OneSecondElapsed += OnTimeElapsed;
+ TimeService.OneSecondElapsed += OnTimeElapsed;
- _timeService.RefreshSecondsElapsed += RefreshData;
- _timeService.RefreshSecondsElapsed += RefreshDisplay;
+ TimeService.RefreshSecondsElapsed += RefreshData;
+ TimeService.RefreshSecondsElapsed += RefreshDisplay;
Initialize();
}
[ObservableProperty]
@@ -74,14 +74,14 @@ namespace CRSim.ScreenSimulator.ViewModels
{
if (trainInfo.DepartureTime == null)
{
- if (trainInfo.ArrivalTime.Value.Add(_settings.StopDisplayFromArrivalDuration) < _timeService.GetDateTimeNow())
+ if (trainInfo.ArrivalTime.Value.Add(_settings.StopDisplayFromArrivalDuration) < TimeService.GetDateTimeNow())
{
itemsToRemove.Add(trainInfo);
}
}
else
{
- if ((StationType == StationType.Arrival || StationType == StationType.Both ? trainInfo.DepartureTime.Value : trainInfo.DepartureTime.Value.Subtract(_settings.StopDisplayUntilDepartureDuration)) < _timeService.GetDateTimeNow())
+ if ((StationType == StationType.Arrival || StationType == StationType.Both ? trainInfo.DepartureTime.Value : trainInfo.DepartureTime.Value.Subtract(_settings.StopDisplayUntilDepartureDuration)) < TimeService.GetDateTimeNow())
{
itemsToRemove.Add(trainInfo);
}
@@ -96,7 +96,7 @@ namespace CRSim.ScreenSimulator.ViewModels
private void OnTimeElapsed(object? sender, EventArgs e)
{
- CurrentTime = _timeService.GetDateTimeNow();
+ CurrentTime = TimeService.GetDateTimeNow();
}
public void LoadData(Station station, string ticketCheck, string platform)
@@ -115,7 +115,7 @@ namespace CRSim.ScreenSimulator.ViewModels
(ticketCheck == string.Empty || (trainNumber.WaitingArea==ticketCheck.Split(" - ")[0] && trainNumber.TicketChecks.Contains(ticketCheck.Split(" - ")[1]))) &&//重复检票口名称的临时解决方案
(platform == string.Empty || trainNumber.Platform == platform))
{
- var now = _timeService.GetDateTimeNow();
+ var now = TimeService.GetDateTimeNow();
var today = now.Date;
if (_settings.LoadTodayOnly && today.Add((trainNumber.DepartureTime??trainNumber.ArrivalTime)!.Value) < now)
diff --git a/CRSim/App.xaml.cs b/CRSim/App.xaml.cs
index 7a3c95c..64403ac 100644
--- a/CRSim/App.xaml.cs
+++ b/CRSim/App.xaml.cs
@@ -24,12 +24,12 @@
services.AddSingleton(parsedOptions);
services.AddSingleton();
services.AddSingleton();
- services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
@@ -43,10 +43,9 @@
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
- AppHost.Services.GetRequiredService().Start();
MainWindow = AppHost.Services.GetService();
MainWindow?.Activate();
- var win = AppHost.Services.GetService();
+ AppHost.Services.GetService();//init
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
diff --git a/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs b/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
index 6f4fc97..84e176b 100644
--- a/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
+++ b/CRSim/ViewModels/ScreenSimulatorPageViewModel.cs
@@ -1,5 +1,4 @@
using CRSim.Core.Models.Plugin;
-using System.Diagnostics.CodeAnalysis;
namespace CRSim.ViewModels;
@@ -44,10 +43,15 @@ public partial class ScreenSimulatorPageViewModel(IServiceProvider serviceProvid
public string SelectedPlatformName = "";
public int SelectedLoaction = 0;
+
[ObservableProperty]
public partial bool IsStartSimulationAvailable { get; private set; } = false;
private PluginBase SelectedStylePlugin => serviceProvider.GetServices().Where(x => x.Info == SelectedStyle).FirstOrDefault();
+ public DateTimeOffset SelectedDate = DateTime.Today;
+
+ public TimeSpan SelectedTime = DateTime.Now - DateTime.Today;
+
[RelayCommand]
public void StyleSelected(object selectedStyle)
{
@@ -139,7 +143,8 @@ public partial class ScreenSimulatorPageViewModel(IServiceProvider serviceProvid
PlatformNeeded ? SelectedPlatformName : string.Empty,
(TextNeeded && Text != string.Empty) ? Text : null,
(LocationNeeded && SelectedLoaction != 0) ? SelectedLoaction : 0,
- (VideoNeeded && Video != string.Empty) ? Video : null);
+ (VideoNeeded && Video != string.Empty) ? Video : null,
+ SelectedDate.Add(SelectedTime).DateTime);
}
private void CheckCanStart()
diff --git a/CRSim/ViewModels/SettingsPageViewModel.cs b/CRSim/ViewModels/SettingsPageViewModel.cs
index 3618d87..f38cc23 100644
--- a/CRSim/ViewModels/SettingsPageViewModel.cs
+++ b/CRSim/ViewModels/SettingsPageViewModel.cs
@@ -20,9 +20,6 @@ namespace CRSim.ViewModels
private readonly IDatabaseService _databaseService;
private readonly IDialogService _dialogService;
#region 偏好设置
- [ObservableProperty]
- public partial string TimeOffset { get; set; }
-
[ObservableProperty]
public partial string DepartureCheckInAdvanceDuration { get; set; }
@@ -69,7 +66,6 @@ namespace CRSim.ViewModels
private void LoadSettings()
{
_settings = _settingsService.GetSettings();
- TimeOffset = _settings.TimeOffset.TotalMinutes.ToString();
DepartureCheckInAdvanceDuration = _settings.DepartureCheckInAdvanceDuration.TotalMinutes.ToString();
PassingCheckInAdvanceDuration = _settings.PassingCheckInAdvanceDuration.TotalMinutes.ToString();
StopDisplayUntilDepartureDuration = _settings.StopDisplayUntilDepartureDuration.TotalMinutes.ToString();
@@ -86,7 +82,6 @@ namespace CRSim.ViewModels
[RelayCommand]
public void Unload()
{
- UpdateSettings(TimeOffset, true, value => _settings.TimeOffset = TimeSpan.FromMinutes(value));
UpdateSettings(DepartureCheckInAdvanceDuration, false, value => _settings.DepartureCheckInAdvanceDuration = TimeSpan.FromMinutes(value));
UpdateSettings(PassingCheckInAdvanceDuration, false, value => _settings.PassingCheckInAdvanceDuration = TimeSpan.FromMinutes(value));
UpdateSettings(StopDisplayUntilDepartureDuration, false, value => _settings.StopDisplayUntilDepartureDuration = TimeSpan.FromMinutes(value));
diff --git a/CRSim/Views/ScreenSimulatorPage.xaml b/CRSim/Views/ScreenSimulatorPage.xaml
index 834faef..ba37535 100644
--- a/CRSim/Views/ScreenSimulatorPage.xaml
+++ b/CRSim/Views/ScreenSimulatorPage.xaml
@@ -75,7 +75,7 @@
-
+
@@ -102,6 +102,12 @@
+
+
+
+
+
+
diff --git a/CRSim/Views/SettingsPage.xaml b/CRSim/Views/SettingsPage.xaml
index c668619..f314ff5 100644
--- a/CRSim/Views/SettingsPage.xaml
+++ b/CRSim/Views/SettingsPage.xaml
@@ -48,9 +48,6 @@
-
-
-