using UIShare.GlobalVariable; using Logger; using Prism.Ioc; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using UIShare.ViewModelBase; namespace TestingModule.ViewModels { public class LogAreaViewModel : NavigateViewModelBase, IDisposable { // 日志集合 private ObservableCollection _logs = new(); public ObservableCollection Logs { get => _logs; set => SetProperty(ref _logs, value); } public ICommand ClearLogCommand { get; set; } private readonly ScopedContext _scopedContext; private readonly GlobalInfo _globalInfo; /// UI 线程定时器,每 100ms 批量从 LogBuffer 出队并刷新 private readonly DispatcherTimer _flushTimer; public LogAreaViewModel(IContainerProvider containerProvider) : base(containerProvider) { ClearLogCommand = new DelegateCommand(ClearLog); _scopedContext = containerProvider.Resolve(); _globalInfo = containerProvider.Resolve(); // UI 线程定时器:每 100ms 从 ScopedContext.LogBuffer 批量出队并 Add _flushTimer = new DispatcherTimer(DispatcherPriority.Normal, System.Windows.Application.Current.Dispatcher) { Interval = TimeSpan.FromMilliseconds(100) }; _flushTimer.Tick += FlushLogBuffer; _flushTimer.Start(); } /// /// 定时批量刷新日志:一次性出队并 Add,WPF 对连续 Add 做合并渲染 /// private void FlushLogBuffer(object? sender, EventArgs e) { if (_scopedContext.LogBuffer.IsEmpty || Logs == null) return; var batch = new List<(string Message, Brush Color, int Depth)>(); while (_scopedContext.LogBuffer.TryDequeue(out var item)) { batch.Add(item); } // 批量 Add,WPF 会对连续 Add 做合并渲染,只触发一次 layout/render pass foreach (var item in batch) { Logs.Add(new LogItem(item.Message, item.Color, item.Depth)); } } private void ClearLog() { // 清空缓冲区,防止定时器下次还把旧数据刷出来 while (_scopedContext.LogBuffer.TryDequeue(out _)) { } Logs?.Clear(); } /// /// 完善后的资源释放方法 /// public void Dispose() { try { // 停止定时器 _flushTimer.Stop(); _flushTimer.Tick -= FlushLogBuffer; // 最后一次刷新缓冲区中的剩余日志 FlushLogBuffer(null, EventArgs.Empty); if (Logs != null) { Logs.Clear(); Logs = null!; } } catch (Exception ex) { Logger.LoggerHelper.ErrorWithNotify( _scopedContext != null ? _globalInfo.CurrentScope : "", $"释放日志组件(LogAreaViewModel)资源失败: {ex.Message}"); } } } // 日志条目类 public class LogItem { public string Message { get; set; } public Brush Color { get; set; } = Brushes.Black; public int Depth { get; set; } public LogItem(string message, Brush color, int depth = 0) { Message = new string(' ', depth * 20) + message; Color = color; Depth = depth; } } }