From f5e2c0e4cb1142784c362e6f1575671c9b67500e Mon Sep 17 00:00:00 2001 From: denglihong2007 <98096191+denglihong2007@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:22:38 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=BF=BB?= =?UTF-8?q?=E9=A1=B5=E5=B1=8F=E9=80=BB=E8=BE=91=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=9B=B4=E6=96=B0=E4=B8=8D=E5=8F=8A=E6=97=B6?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/BaseScreenViewModel.cs | 320 +++++++++--------- CRSim/Package.appxmanifest | 2 +- 2 files changed, 160 insertions(+), 162 deletions(-) diff --git a/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs b/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs index fed03c0..8165f3a 100644 --- a/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs +++ b/CRSim.ScreenSimulator/ViewModels/BaseScreenViewModel.cs @@ -4,59 +4,29 @@ using CRSim.Core.Models; using CRSim.ScreenSimulator.Abstractions; using CRSim.ScreenSimulator.Models; using System.Collections.ObjectModel; -using System.Linq; -using System.Windows; namespace CRSim.ScreenSimulator.ViewModels { - public partial class BaseScreenViewModel : ObservableObject,IScreenViewModel + public partial class BaseScreenViewModel : ObservableObject, IScreenViewModel { public ITimeService TimeService { get; set; } public readonly Settings _settings; public readonly TaskCompletionSource DataLoaded = new(); - [ObservableProperty] - private DateTime _currentTime = new(); - [ObservableProperty] - private string _text = ""; - [ObservableProperty] - public int _location; - [ObservableProperty] - private Station _thisStation; - [ObservableProperty] - private string _thisPlatform; - [ObservableProperty] - private string _thisTicketCheck; - [ObservableProperty] - private Uri _video; + + [ObservableProperty] private DateTime _currentTime = new(); + [ObservableProperty] private string _text = ""; + [ObservableProperty] public int _location; + [ObservableProperty] private Station _thisStation; + [ObservableProperty] private string _thisPlatform; + [ObservableProperty] private string _thisTicketCheck; + [ObservableProperty] private Uri _video; + [ObservableProperty] private int _currentPageIndex = 0; + public ObservableCollection ScreenA { get; private set; } = []; - public ObservableCollection ScreenB { get; private set; } = []; + public ObservableCollection ScreenB { get; private set; } = []; public System.Windows.Threading.Dispatcher UIDispatcher { get; set; } - public List TrainInfo { get; set; } = []; - public StationType StationType = StationType.Both; - - protected BaseScreenViewModel(ITimeService timeService, ISettingsService settingsService) - { - - TimeService = timeService; - _settings = settingsService.GetSettings(); - - TimeService.OneSecondElapsed += OnTimeElapsed; - - TimeService.RefreshSecondsElapsed += RefreshData; - TimeService.RefreshSecondsElapsed += RefreshDisplay; - Initialize(); - } - [ObservableProperty] - private int _currentPageIndex = 0; - public int PageCount - { - get - { - return Math.Min((int)Math.Ceiling((double)TrainInfo.Count / ItemsPerPage * ScreenCount.Value),_settings.MaxPages); - } - } public int ItemsPerPage = 1; // @@ -64,67 +34,170 @@ namespace CRSim.ScreenSimulator.ViewModels // public int? ScreenCount = null; - private async void Initialize() + private TrainInfo nullTrainInfo = new(); + + public int PageCount { - await DataLoaded.Task; - RefreshDisplay(null, null); - } - public void RefreshData(object? sender, EventArgs e) - { - if (CurrentPageIndex == 0) + get { - List itemsToRemove = []; - foreach(TrainInfo trainInfo in TrainInfo) - { - if (trainInfo.DepartureTime == null) - { - 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()) - { - itemsToRemove.Add(trainInfo); - } - } - } - foreach (var item in itemsToRemove) - { - TrainInfo.Remove(item); - } + if (ScreenCount == null || ScreenCount == 0) return 1; + return Math.Min((int)Math.Ceiling((double)TrainInfo.Count / (ItemsPerPage * ScreenCount.Value)), _settings.MaxPages); } } + protected BaseScreenViewModel(ITimeService timeService, ISettingsService settingsService) + { + TimeService = timeService; + _settings = settingsService.GetSettings(); + + // 每秒执行一次:包含数据清理和 UI 重建 + TimeService.OneSecondElapsed += OnTimeElapsed; + + // 仅执行翻页逻辑(例如每 10 秒切换一次页码) + TimeService.RefreshSecondsElapsed += RefreshDisplay; + + Initialize(); + } + + private async void Initialize() + { + await DataLoaded.Task; + UpdateVisuals(); // 初始渲染 + } + + /// + /// 每秒触发的核心逻辑 + /// private void OnTimeElapsed(object? sender, EventArgs e) { CurrentTime = TimeService.GetDateTimeNow(); - OnPropertyChanged(nameof(ScreenA)); - OnPropertyChanged(nameof(ScreenB)); + + // 1. 检查并删除过期车次 + CleanExpiredData(); + + // 2. 重新构建显示内容(清空并重新添加) + UpdateVisuals(); } + /// + /// 仅负责翻页更改索引 + /// + public virtual void RefreshDisplay(object? sender, EventArgs e) + { + int totalPages = PageCount; + if (totalPages <= 1) + { + CurrentPageIndex = 0; + return; + } + + // 循环翻页逻辑 + CurrentPageIndex = (CurrentPageIndex + 1 >= totalPages) ? 0 : CurrentPageIndex + 1; + } + + /// + /// 核心渲染方法:删除所有元素并根据当前 PageIndex 重新填充 + /// + private void UpdateVisuals() + { + UIDispatcher.Invoke(() => + { + // 清空当前显示的所有元素 + ScreenA.Clear(); + ScreenB.Clear(); + + if (ScreenCount == null) + { + // 非翻页模式:始终显示前 N 条 + for (int i = 0; i < ItemsPerPage; i++) + { + ScreenA.Add(TrainInfo.Count > i ? TrainInfo[i] : nullTrainInfo); + } + return; + } + + // 翻页模式:根据 CurrentPageIndex 计算起始点 + int startIndex = CurrentPageIndex * ItemsPerPage * ScreenCount.Value; + + // 填充 ScreenA + var leftItems = TrainInfo.Skip(startIndex).Take(ItemsPerPage).ToList(); + while (leftItems.Count < ItemsPerPage) leftItems.Add(nullTrainInfo); + foreach (var item in leftItems) ScreenA.Add(item); + + // 如果是双屏模式,填充 ScreenB + if (ScreenCount >= 2) + { + var rightItems = TrainInfo.Skip(startIndex + ItemsPerPage).Take(ItemsPerPage).ToList(); + while (rightItems.Count < ItemsPerPage) rightItems.Add(nullTrainInfo); + foreach (var item in rightItems) ScreenB.Add(item); + } + }); + } + + /// + /// 数据清理逻辑:检查并移除不再需要显示的车次 + /// + private void CleanExpiredData() + { + var now = TimeService.GetDateTimeNow(); + bool changed = false; + + // 使用倒序或创建临时列表移除,防止遍历冲突 + for (int i = TrainInfo.Count - 1; i >= 0; i--) + { + var train = TrainInfo[i]; + bool shouldRemove = false; + + if (train.DepartureTime == null) // 终到车 + { + if (train.ArrivalTime.Value.Add(_settings.StopDisplayFromArrivalDuration) < now) + shouldRemove = true; + } + else // 始发或过路车 + { + var referenceTime = (StationType == StationType.Arrival || StationType == StationType.Both) + ? train.DepartureTime.Value + : train.DepartureTime.Value.Subtract(_settings.StopDisplayUntilDepartureDuration); + + if (referenceTime < now) + shouldRemove = true; + } + + if (shouldRemove) + { + TrainInfo.RemoveAt(i); + changed = true; + } + } + + // 如果删除了数据导致总页数变少,重置索引防止越界 + if (changed && CurrentPageIndex >= PageCount) + { + CurrentPageIndex = 0; + } + } + + /// + /// 原始数据加载(保持不变) + /// public void LoadData(Station station, TicketCheck? ticketCheck, string platform) { ThisStation = station; ThisPlatform = platform; ThisTicketCheck = ticketCheck?.Name; + var trains = station.TrainStops; foreach (var trainNumber in trains) { - if (trainNumber != null && - (StationType == StationType.Both || - trainNumber.StationType == StationType.Both || - StationType == trainNumber.StationType) && + (StationType == StationType.Both || trainNumber.StationType == StationType.Both || StationType == trainNumber.StationType) && (ticketCheck == null || trainNumber.TicketCheckIds.Contains(ticketCheck.Id)) && (platform == string.Empty || trainNumber.Platform == platform)) { var now = TimeService.GetDateTimeNow(); var today = now.Date; - if (_settings.LoadTodayOnly && today.Add((trainNumber.DepartureTime??trainNumber.ArrivalTime)!.Value).Add(trainNumber.Status.Value) < now) + if (_settings.LoadTodayOnly && today.Add((trainNumber.DepartureTime ?? trainNumber.ArrivalTime)!.Value).Add(trainNumber.Status.Value) < now) { continue; } @@ -137,101 +210,26 @@ namespace CRSim.ScreenSimulator.ViewModels TrainNumber = trainNumber.Number, Terminal = trainNumber.Terminal, Origin = trainNumber.Origin, - ArrivalTime = AdjustTime(trainNumber.ArrivalTime,trainNumber.Status), + ArrivalTime = AdjustTime(trainNumber.ArrivalTime, trainNumber.Status), DepartureTime = trainNumber.Status > TimeSpan.Zero ? AdjustTime(trainNumber.DepartureTime, trainNumber.Status) : AdjustTime(trainNumber.DepartureTime, TimeSpan.Zero), TicketChecks = trainNumber.TicketCheckIds is null ? [] : [.. station.WaitingAreas .SelectMany(w => w.TicketChecks) .Where(tc => trainNumber.TicketCheckIds.Contains(tc.Id)) .Select(tc => tc.Name)], - WaitingArea = trainNumber.StationType == StationType.Arrival ? string.Empty : string.Join(" ", station.WaitingAreas.Where(x => x.TicketChecks.Any(y => trainNumber.TicketCheckIds.Contains(y.Id))).Select(x=>x.Name)), + WaitingArea = trainNumber.StationType == StationType.Arrival ? string.Empty : string.Join(" ", station.WaitingAreas.Where(x => x.TicketChecks.Any(y => trainNumber.TicketCheckIds.Contains(y.Id))).Select(x => x.Name)), Platform = trainNumber.Platform, Length = trainNumber.Length, Landmark = trainNumber.Landmark, State = trainNumber.Status }); - } } - if(StationType == StationType.Arrival) - { - TrainInfo = [.. TrainInfo.OrderBy(x => x.ArrivalTime??x.DepartureTime)]; - } - else - { - TrainInfo = [.. TrainInfo.OrderBy(x => x.DepartureTime??x.ArrivalTime)]; - } - RefreshData(null, null); + + TrainInfo = StationType == StationType.Arrival + ? [.. TrainInfo.OrderBy(x => x.ArrivalTime ?? x.DepartureTime)] + : [.. TrainInfo.OrderBy(x => x.DepartureTime ?? x.ArrivalTime)]; + DataLoaded.SetResult(true); } - public virtual void RefreshDisplay(object? sender, EventArgs e) - { - UIDispatcher.Invoke(() => - { - if (ScreenCount == null) - { - for (int i = 0; i < ItemsPerPage; i++) - { - ScreenA.Add(TrainInfo.Count > i ? TrainInfo[i] : new()); - } - if (ScreenA.Count > ItemsPerPage) - { - for (int i = 0; i < ItemsPerPage; i++) - { - ScreenA.RemoveAt(0); - } - } - return; - } - int pageCount = (int)Math.Ceiling((double)TrainInfo.Count / (ItemsPerPage * ScreenCount.Value)); - int startIndex = CurrentPageIndex * ItemsPerPage * ScreenCount.Value; - - switch (ScreenCount) - { - case 1: - { - ScreenA.Clear(); - var items = TrainInfo.Skip(startIndex).Take(ItemsPerPage).ToList(); - while (items.Count < ItemsPerPage) - { - items.Add(new TrainInfo()); - } - foreach (var item in items) - { - ScreenA.Add(item); - } - break; - } - case 2: - { - ScreenA.Clear(); - ScreenB.Clear(); - - var leftItems = TrainInfo.Skip(startIndex).Take(ItemsPerPage).ToList(); - while (leftItems.Count < ItemsPerPage) - { - leftItems.Add(new TrainInfo()); - } - foreach (var item in leftItems) - { - ScreenA.Add(item); - } - - var rightItems = TrainInfo.Skip(startIndex + ItemsPerPage).Take(ItemsPerPage).ToList(); - while (rightItems.Count < ItemsPerPage) - { - rightItems.Add(new TrainInfo()); - } - foreach (var item in rightItems) - { - ScreenB.Add(item); - } - break; - } - } - - CurrentPageIndex = CurrentPageIndex + 1 >= Math.Min(_settings.MaxPages, pageCount) ? 0 : CurrentPageIndex + 1; - }); - } - } -} +} \ No newline at end of file diff --git a/CRSim/Package.appxmanifest b/CRSim/Package.appxmanifest index 4a00897..69c7949 100644 --- a/CRSim/Package.appxmanifest +++ b/CRSim/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="3.2.0.0" />