namespace ServiceLib.ViewModels; public partial class MsgViewModel : MyReactiveObject { public Interaction DispatcherShowMsgInteraction { get; } = new(); private readonly ConcurrentQueue _queueMsg = new(); private volatile bool _lastMsgFilterNotAvailable; private int _showLock = 0; // 0 = unlocked, 1 = locked public int NumMaxMsg { get; } = 500; [Reactive] public partial string MsgFilter { get; set; } [Reactive] public partial bool AutoRefresh { get; set; } public MsgViewModel() { _config = AppManager.Instance.Config; MsgFilter = _config.MsgUIItem.MainMsgFilter ?? string.Empty; AutoRefresh = _config.MsgUIItem.AutoRefresh ?? true; this.WhenAnyValue( x => x.MsgFilter) .Subscribe(c => DoMsgFilter()); this.WhenAnyValue( x => x.AutoRefresh, y => y == true) .Subscribe(c => _config.MsgUIItem.AutoRefresh = AutoRefresh); AppEvents.SendMsgViewRequested .AsObservable() //.ObserveOn(RxSchedulers.MainThreadScheduler) .Subscribe(content => _ = AppendQueueMsg(content)); } public void FlushQueueMsg() { _ = AppendQueueMsg(string.Empty); } private async Task AppendQueueMsg(string msg) { if (AutoRefresh == false) { return; } EnqueueQueueMsg(msg); if (!AppManager.Instance.ShowInTaskbar) { return; } if (Interlocked.CompareExchange(ref _showLock, 1, 0) != 0) { return; } try { await Task.Delay(500).ConfigureAwait(false); var sb = new StringBuilder(); while (_queueMsg.TryDequeue(out var line)) { sb.Append(line); } if (sb.Length > 0) { try { await DispatcherShowMsgInteraction.HandleSafe(sb.ToString()); } catch (Exception) { _queueMsg.Enqueue(sb.ToString()); } } } finally { Interlocked.Exchange(ref _showLock, 0); } } private void EnqueueQueueMsg(string msg) { if (string.IsNullOrEmpty(msg)) { return; } //filter msg if (MsgFilter.IsNotEmpty() && !_lastMsgFilterNotAvailable) { try { if (!Regex.IsMatch(msg, MsgFilter)) { return; } } catch (Exception ex) { EnqueueWithLimit(ex.Message); _lastMsgFilterNotAvailable = true; } } EnqueueWithLimit(msg); if (!msg.EndsWith(Environment.NewLine)) { EnqueueWithLimit(Environment.NewLine); } } private void EnqueueWithLimit(string item) { _queueMsg.Enqueue(item); while (_queueMsg.Count > NumMaxMsg) { _queueMsg.TryDequeue(out _); } } //public void ClearMsg() //{ // _queueMsg.Clear(); //} private void DoMsgFilter() { _config.MsgUIItem.MainMsgFilter = MsgFilter; _lastMsgFilterNotAvailable = false; } }