Dreamine.Logging.Wpf 1.0.2
Dreamine.Logging.Wpf 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
DreamineLogPanelViewModel.cs
이 파일의 문서화 페이지로 가기
1using System;
2using System.Collections.Generic;
3using System.Collections.ObjectModel;
4using System.Collections.Specialized;
5using System.ComponentModel;
6using System.Runtime.CompilerServices;
7using System.Windows.Threading;
8using Dreamine.Logging.Interfaces;
9using Dreamine.Logging.Models;
11
13{
30 public sealed class DreamineLogPanelViewModel : INotifyPropertyChanged, IDisposable
31 {
40 public const int DefaultDisplayCapacity = 1000;
41
50 private readonly IDreamineLogStore _logStore;
59 private readonly BatchedDispatcher<DreamineLogEntry?> _uiDispatcher;
68 private readonly int _displayCapacity;
77 private DreamineLogEntry? _selectedEntry;
86 private bool _autoScroll = true;
95 private bool _disposed;
96
105 public event PropertyChangedEventHandler? PropertyChanged;
106
115 public event EventHandler<DreamineLogEntry>? EntryAppended;
116
125 public ObservableCollection<DreamineLogEntry> Entries { get; } = new LogEntryCollection();
126
143 public bool AutoScroll
144 {
145 get => _autoScroll;
146 set
147 {
148 if (_autoScroll == value)
149 {
150 return;
151 }
152
153 _autoScroll = value;
155 }
156 }
157
166 public DreamineLogEntry? SelectedEntry
167 {
168 get => _selectedEntry;
169 set
170 {
171 if (ReferenceEquals(_selectedEntry, value))
172 {
173 return;
174 }
175
176 _selectedEntry = value;
179 }
180 }
181
190 public string SelectedDetailText => SelectedEntry?.DisplayText ?? string.Empty;
191
217 IDreamineLogStore logStore,
218 ILogUiDispatcher dispatcher)
219 : this(logStore, dispatcher, DefaultDisplayCapacity)
220 {
221 }
222
264 IDreamineLogStore logStore,
265 ILogUiDispatcher dispatcher,
266 int displayCapacity)
267 {
268 _logStore = logStore ?? throw new ArgumentNullException(nameof(logStore));
269 ArgumentNullException.ThrowIfNull(dispatcher);
270
271 _displayCapacity = displayCapacity > 0 ? displayCapacity : DefaultDisplayCapacity;
272
273 _uiDispatcher = new BatchedDispatcher<DreamineLogEntry?>(
274 dispatcher.Dispatcher,
276 DispatcherPriority.Background);
277
278 // Seed with whatever the store already has, capped to display capacity.
279 var existing = _logStore.GetEntries();
280 var skip = Math.Max(0, existing.Count - _displayCapacity);
281 for (var i = skip; i < existing.Count; i++)
282 {
283 Entries.Add(existing[i]);
284 }
285
286 _logStore.LogAdded += OnLogAdded;
287 }
288
305 public void Clear()
306 {
307 _logStore.Clear();
308
309 // Sentinel: null indicates "clear" within the batch stream.
310 _uiDispatcher.Enqueue(null);
311 }
312
321 public void Dispose()
322 {
323 if (_disposed)
324 {
325 return;
326 }
327
328 _disposed = true;
329 _logStore.LogAdded -= OnLogAdded;
330 }
331
356 private void OnLogAdded(object? sender, DreamineLogEntry entry)
357 {
358 if (_disposed)
359 {
360 return;
361 }
362
363 // Producer side: any thread. Just enqueue.
364 _uiDispatcher.Enqueue(entry);
365 }
366
383 private void OnEntriesBatch(IReadOnlyList<DreamineLogEntry?> batch)
384 {
385 // UI thread.
386 if (_disposed)
387 {
388 return;
389 }
390
391 DreamineLogEntry? lastAppended = null;
392
393 foreach (var entry in batch)
394 {
395 if (entry is null)
396 {
397 // Clear sentinel.
398 Entries.Clear();
399 SelectedEntry = null;
400 lastAppended = null;
401 continue;
402 }
403
404 Entries.Add(entry);
405 lastAppended = entry;
406 }
407
408 // Enforce display cap. Trim from the front in one reset notification.
409 var overflow = Entries.Count - _displayCapacity;
410 if (overflow > 0 && Entries is LogEntryCollection logEntries)
411 {
412 logEntries.TrimStart(overflow);
413 }
414
415 if (lastAppended is not null)
416 {
417 if (_autoScroll)
418 {
419 SelectedEntry = lastAppended;
420 }
421
422 EntryAppended?.Invoke(this, lastAppended);
423 }
424 }
425
442 private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
443 {
444 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
445 }
446
455 private sealed class LogEntryCollection : ObservableCollection<DreamineLogEntry>
456 {
473 public void TrimStart(int count)
474 {
475 if (count <= 0)
476 {
477 return;
478 }
479
480 int removeCount = Math.Min(count, Items.Count);
481 for (var i = 0; i < removeCount; i++)
482 {
483 Items.RemoveAt(0);
484 }
485
486 OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
487 OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
488 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
489 }
490 }
491 }
492}
void OnPropertyChanged([CallerMemberName] string? propertyName=null)
void OnEntriesBatch(IReadOnlyList< DreamineLogEntry?> batch)
DreamineLogPanelViewModel(IDreamineLogStore logStore, ILogUiDispatcher dispatcher)
DreamineLogPanelViewModel(IDreamineLogStore logStore, ILogUiDispatcher dispatcher, int displayCapacity)
readonly BatchedDispatcher< DreamineLogEntry?> _uiDispatcher