diff --git a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs index 71d5548..69a162b 100644 --- a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs @@ -18,6 +18,8 @@ namespace Needlework.Net.Desktop.ViewModels public partial class WebsocketViewModel : PageBase { public ObservableCollection EventLog { get; } = []; + public SemaphoreSlim EventLogLock { get; } = new(1, 1); + [NotifyPropertyChangedFor(nameof(FilteredEventLog))] [ObservableProperty] private string _search = string.Empty; [ObservableProperty] private bool _isAttach = true; @@ -94,25 +96,34 @@ namespace Needlework.Net.Desktop.ViewModels private void OnMessage(EventMessage message) { - Avalonia.Threading.Dispatcher.UIThread.Invoke(() => + Avalonia.Threading.Dispatcher.UIThread.Invoke(async () => { if (!IsAttach) return; var line = $"{DateTime.Now:HH:mm:ss.fff} {message.Data?.EventType.ToUpper()} {message.Data?.Uri}"; Trace.WriteLine($"Message: {line}"); - if (EventLog.Count < 1000) - { - EventLog.Add(line); - _events[line] = message; - } - else - { - var key = EventLog[0]; - EventLog.RemoveAt(0); - _events.Remove(key); - EventLog.Add(line); - _events[line] = message; + await EventLogLock.WaitAsync(); + try + { + if (EventLog.Count < 1000) + { + EventLog.Add(line); + _events[line] = message; + } + else + { + var key = EventLog[0]; + EventLog.RemoveAt(0); + _events.Remove(key); + + EventLog.Add(line); + _events[line] = message; + } + } + finally + { + EventLogLock.Release(); } }); } diff --git a/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs b/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs index c751251..af1ec95 100644 --- a/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs +++ b/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs @@ -7,6 +7,7 @@ using CommunityToolkit.Mvvm.Messaging; using Needlework.Net.Desktop.Extensions; using Needlework.Net.Desktop.Messages; using Needlework.Net.Desktop.ViewModels; +using System; using TextMateSharp.Grammars; namespace Needlework.Net.Desktop.Views; @@ -14,6 +15,8 @@ namespace Needlework.Net.Desktop.Views; public partial class WebsocketView : UserControl, IRecipient { private TextEditor? _responseEditor; + public WebsocketViewModel? _viewModel; + private ListBox? _viewer; public WebsocketView() { @@ -29,9 +32,9 @@ public partial class WebsocketView : UserControl, IRecipient("EventViewer"); - vm.EventLog.CollectionChanged += (s, e) => { if (vm.IsTail) viewer!.ScrollIntoView(vm.EventLog.Count - 1); }; + _viewModel = (WebsocketViewModel)DataContext!; + _viewer = this.FindControl("EventViewer"); + _viewModel.EventLog.CollectionChanged += EventLog_CollectionChanged; ; _responseEditor = this.FindControl("ResponseEditor"); _responseEditor?.ApplyJsonEditorSettings(); @@ -41,6 +44,26 @@ public partial class WebsocketView : UserControl, IRecipient + { + if (_viewModel!.IsTail) + { + await _viewModel.EventLogLock.WaitAsync(); + try + { + _viewer!.ScrollIntoView(_viewModel.EventLog.Count - 1); + } + catch (InvalidOperationException) { } + finally + { + _viewModel.EventLogLock.Release(); + } + } + }); + } + private void OnBaseThemeChanged(ThemeVariant currentTheme) {