Dreamine.Logging.Wpf
1.0.1
dotnet add package Dreamine.Logging.Wpf --version 1.0.1
NuGet\Install-Package Dreamine.Logging.Wpf -Version 1.0.1
<PackageReference Include="Dreamine.Logging.Wpf" Version="1.0.1" />
<PackageVersion Include="Dreamine.Logging.Wpf" Version="1.0.1" />
<PackageReference Include="Dreamine.Logging.Wpf" />
paket add Dreamine.Logging.Wpf --version 1.0.1
#r "nuget: Dreamine.Logging.Wpf, 1.0.1"
#:package Dreamine.Logging.Wpf@1.0.1
#addin nuget:?package=Dreamine.Logging.Wpf&version=1.0.1
#tool nuget:?package=Dreamine.Logging.Wpf&version=1.0.1
Dreamine.Logging.Wpf
Dreamine.Logging.Wpf provides WPF-specific logging UI components for Dreamine applications.
It connects Dreamine.Logging to WPF through a log panel view, a bounded log panel view model, and UI dispatcher helpers designed for high-frequency log updates.
Purpose
This package is responsible only for WPF presentation and UI-thread integration.
The core logging pipeline, sinks, formatters, and async queue are provided by Dreamine.Logging.
Dreamine.Logging.Wpf depends on Dreamine.Logging.
Dreamine.Logging must not depend on WPF.
Features
DreamineLogPanelViewfor displaying logs in WPFDreamineLogPanelViewModelfor binding log entries to the UI- Bounded visible log collection with
DefaultDisplayCapacity = 1000 - Batched UI update delivery through
BatchedDispatcher<T> WpfLogUiDispatcherfor WPF Dispatcher access- Real-time log display through
IDreamineLogStore.LogAdded - Clear support through
DreamineLogPanelViewModel.Clear() - Auto-select/auto-scroll support through
AutoScrollandEntryAppended - Log detail display for selected entries
- Event unsubscription through
Dispose()to prevent ViewModel retention
Recommended Architecture
The WPF package should observe the in-memory log store only. It should not write files, own the logger, or create the async queue.
[Dreamine.Logging]
Logger
└─► AsyncQueueSink
└─► CompositeLogSink
├─► InMemoryLogStore ──(LogAdded event)──┐
└─► TextFileLogSink │
▼
[Dreamine.Logging.Wpf]
DreamineLogPanelViewModel
└─► DreamineLogPanelView
DreamineLogPanelViewModel is not a child of the sink chain.
It is a separate observer that subscribes to InMemoryLogStore.LogAdded,
and forwards updates to the UI thread in batches via BatchedDispatcher<T>.
Why Batched UI Dispatch Exists
A log panel can receive log events from many worker threads.
If each log entry schedules a separate Dispatcher.BeginInvoke, the WPF Dispatcher queue can grow faster than the UI can process it.
This creates memory pressure and makes the UI feel frozen.
BatchedDispatcher<T> coalesces many incoming log entries into a limited UI-thread batch:
- producers enqueue from any thread;
- only one dispatcher operation is scheduled at a time;
- each UI batch processes up to
MaxBatchSizeentries; - additional entries are processed in the next pass;
- visible entries are trimmed to the configured display capacity.
Example XAML Usage
<UserControl x:Class="SampleSmart.Pages.PageSub.PageLog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:logViews="clr-namespace:Dreamine.Logging.Wpf.Views;assembly=Dreamine.Logging.Wpf">
<Grid>
<logViews:DreamineLogPanelView DataContext="{Binding LogPanel}" />
</Grid>
</UserControl>
Example ViewModel Wrapper
public sealed class PageLogViewModel : ViewModelBase
{
public DreamineLogPanelViewModel LogPanel { get; }
public PageLogViewModel(DreamineLogPanelViewModel logPanel)
{
LogPanel = logPanel;
}
}
Example Registration
The log store must be registered by the core logging registration. The WPF package only needs the UI dispatcher and log panel view model registration.
DMContainer.RegisterSingleton<WpfLogUiDispatcher>(
new WpfLogUiDispatcher());
DMContainer.Register<DreamineLogPanelViewModel>(() =>
new DreamineLogPanelViewModel(
DMContainer.Resolve<IDreamineLogStore>(),
DMContainer.Resolve<WpfLogUiDispatcher>()));
If a custom visible capacity is needed:
DMContainer.Register<DreamineLogPanelViewModel>(() =>
new DreamineLogPanelViewModel(
DMContainer.Resolve<IDreamineLogStore>(),
DMContainer.Resolve<WpfLogUiDispatcher>(),
displayCapacity: 2000));
Full Logging + WPF Registration Example
private static AsyncQueueSink? _asyncLogSink;
private static void RegisterLogging()
{
var logStore = new InMemoryLogStore(capacity: 1000);
var formatter = new DreamineTextLogFormatter();
var textFileSink = new TextFileLogSink(
Path.Combine(AppContext.BaseDirectory, "Logs"),
formatter,
flushEveryWriteCount: 20);
var compositeSink = new CompositeLogSink(new IDreamineLogSink[]
{
logStore,
textFileSink
});
_asyncLogSink = new AsyncQueueSink(
compositeSink,
capacity: 8192,
drainBatchSize: 256);
// Note: DreamineLogger currently has no (single sink, level, category)
// overload, so even a single sink is wrapped as IEnumerable<IDreamineLogSink>.
var logger = new DreamineLogger(
new IDreamineLogSink[] { _asyncLogSink },
DreamineLogLevel.Trace,
category: "SampleSmart");
DMContainer.RegisterSingleton(logStore);
DMContainer.RegisterSingleton<IDreamineLogStore>(logStore);
DMContainer.RegisterSingleton<IDreamineLogFormatter>(formatter);
DMContainer.RegisterSingleton<IDreamineLogSink>(_asyncLogSink);
DMContainer.RegisterSingleton<IDreamineLogger>(logger);
DMContainer.RegisterSingleton<WpfLogUiDispatcher>(new WpfLogUiDispatcher());
DMContainer.Register<DreamineLogPanelViewModel>(() =>
new DreamineLogPanelViewModel(
DMContainer.Resolve<IDreamineLogStore>(),
DMContainer.Resolve<WpfLogUiDispatcher>()));
}
Shutdown
When the logger uses AsyncQueueSink, drain pending logs on application shutdown.
protected override void OnExit(ExitEventArgs e)
{
try
{
_asyncLogSink?.ShutdownAsync(TimeSpan.FromSeconds(2))
.GetAwaiter()
.GetResult();
}
catch
{
// Shutdown errors must not prevent process exit.
}
finally
{
base.OnExit(e);
}
}
OnExit is a synchronous method, so use GetAwaiter().GetResult() rather than
async void to ensure the process does not exit before the queue is drained.
Important Notes
DreamineLogPanelView must receive a DreamineLogPanelViewModel as its DataContext.
When wrapping the log panel inside another page, bind the inner view's DataContext explicitly.
<logViews:DreamineLogPanelView DataContext="{Binding LogPanel}" />
The detail text binding should use Mode=OneWay because the detail text is read-only.
<TextBox Text="{Binding SelectedDetailText, Mode=OneWay}" />
Dispose DreamineLogPanelViewModel when the owning page or window is permanently destroyed.
This unsubscribes from IDreamineLogStore.LogAdded and prevents the ViewModel from being retained by the event source.
Performance Notes
- The visible
Entriescollection is capped, so it does not grow forever. - UI updates are batched instead of scheduling one Dispatcher operation per log entry.
- The log panel is suitable for diagnostics and monitoring, not for storing unlimited historical logs.
- For long-term history, use
TextFileLogSinkor another persistent sink inDreamine.Logging. - Avoid logging every cycle in production thread loops unless diagnostic mode is enabled.
Relationship with Dreamine.Logging
Dreamine.Logging.Wpf
-> Dreamine.Logging
The dependency direction must remain one-way. The WPF package is a presentation adapter over the core logging package.
Future Roadmap
DMContainer.UseDreamineLoggingWpf()(registers UI dispatcher and panel view model in one line)DMContainer.UseDreamineLoggingForWpf(...)(a unified entry point that performs both core and WPF registration at once)- Built-in clear command binding
- Log level filter
- Search/filter UI
- Export selected logs
- Optional auto-scroll behavior helper
- Optional status indicator for dropped async logs (UI exposing
AsyncQueueSink.DroppedCount)
License
MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows7.0
- Dreamine.Logging (>= 1.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Dreamine.Logging.Wpf:
| Package | Downloads |
|---|---|
|
Dreamine.MVVM.FullKit
All-in-one package for Dreamine MVVM on WPF. Includes core MVVM modules and automatic source generator integration. |
GitHub repositories
This package is not used by any popular GitHub repositories.