LogViewerControl

June 6, 2026 ยท View on GitHub

Scrollable control that displays log entries from the library's LogService, updating automatically as new entries arrive.

Overview

LogViewerControl renders the entries held by an ILogService as a live, scrolling list. It subscribes to the service's LogAdded and LogsCleared events, so the view updates automatically whenever the application or the library writes a log entry. Each entry is rendered through LogEntry.ToMarkup(), which color-codes the level and dims the timestamp and category.

Internally the control wraps a ScrollablePanelControl (with AutoScroll enabled), so it inherits smooth scrolling, an optional scrollbar, and mouse-wheel support. New entries appended at the bottom automatically scroll into view unless the user has scrolled away. The control honors the service's MaxBufferSize, trimming the oldest displayed entries when the buffer overflows.

LogViewerControl is thread-safe: log events may be raised from any thread. Incoming entries are placed on a concurrent queue and applied on the UI thread during the next paint, so background logging never races with rendering. The control supports an optional Title line and can filter what it shows by minimum log level and by category.

See also: ListControl, MarkupControl

Quick Start

var logViewer = new LogViewerControl(windowSystem.LogService)
{
    Title = "Library Logs"
};

var window = new WindowBuilder(windowSystem)
    .WithTitle("Log Viewer")
    .WithSize(80, 25)
    .Centered()
    .AddControl(logViewer)
    .BuildAndShow();

There is no fluent builder or Controls.LogViewer() factory for this control. Construct it directly with its constructor, passing an ILogService (typically windowSystem.LogService).

Construction

LogViewerControl has a single constructor that binds it to a log service:

public LogViewerControl(ILogService logService)
ParameterTypeDescription
logServiceILogServiceThe log service whose entries are displayed. Must not be null (throws ArgumentNullException). Existing entries are loaded immediately; new entries appear as they are logged.
// Bind to the window system's built-in log service
var viewer = new LogViewerControl(windowSystem.LogService);

// Configure via object initializer
var viewer = new LogViewerControl(windowSystem.LogService)
{
    Title = "Diagnostics",
    AutoScroll = true,
    FilterLevel = LogLevel.Information,
    Name = "logViewer"
};

Properties

PropertyTypeDefaultDescription
AutoScrollbooltrueWhether to automatically scroll to show new entries. Delegates to the internal ScrollablePanelControl.
FilterLevelLogLevelLogLevel.TraceMinimum log level to display; entries below this level are filtered out. Changing it refreshes the view.
FilterCategorystring?nullCategory filter. When null, all categories are shown; otherwise only entries whose Category matches exactly. Changing it refreshes the view.
Titlestring?nullOptional title rendered on a single line above the entries (markup-formatted). When focused, the title is shown in cyan; otherwise grey.
IsEnabledbooltrueEnables or disables interaction (keyboard handling and focus).
HasFocusbool(computed)Whether the control currently has keyboard focus.
CanReceiveFocusbool(computed)True when the control is visible and enabled.
WantsMouseEventsbooltrueIndicates the control consumes mouse events.

Standard BaseControl members such as Name, Width, Visible, Margin, and HorizontalAlignment also apply.

Events

EventArgumentsDescription
MouseClickEventHandler<MouseEventArgs>Declared for interface compatibility; not raised by this control.
MouseDoubleClickEventHandler<MouseEventArgs>Declared for interface compatibility; not raised by this control.
MouseRightClickEventHandler<MouseEventArgs>Fired when the control is right-clicked (mouse button 3).
MouseEnterEventHandler<MouseEventArgs>Declared for interface compatibility; not raised by this control.
MouseLeaveEventHandler<MouseEventArgs>Declared for interface compatibility; not raised by this control.
MouseMoveEventHandler<MouseEventArgs>Declared for interface compatibility; not raised by this control.

The log content itself comes from the bound ILogService. To react to new log entries programmatically, subscribe to ILogService.LogAdded rather than to this control's events.

Keyboard Support

KeyAction
Up ArrowScroll up one line
Down ArrowScroll down one line
Page UpScroll up by one viewport height
Page DownScroll down by one viewport height
HomeScroll to the top
EndScroll to the bottom
DeleteClear all logs (calls LogService.ClearLogs())
Ctrl+CClear all logs (calls LogService.ClearLogs())

Keyboard input is only processed when the control is enabled and focused.

Mouse Support

ActionResult
Right ClickFires MouseRightClick
Scroll WheelScrolls the log up/down (handled by the internal scroll panel)
Other mouse eventsDelegated to the internal ScrollablePanelControl

Examples

Basic Log Viewer Window

var logViewer = new LogViewerControl(ws.LogService)
{
    Title = "Library Logs",
    Name = "logViewer"
};

var window = new WindowBuilder(ws)
    .WithTitle("Log Viewer")
    .WithSize(80, 25)
    .Centered()
    .AddControl(logViewer)
    .OnKeyPressed((s, e) =>
    {
        if (e.KeyInfo.Key == ConsoleKey.Escape)
        {
            ws.CloseWindow((Window)s!);
            e.Handled = true;
        }
    })
    .BuildAndShow();

Filtering by Level

// Only show warnings and above
var viewer = new LogViewerControl(windowSystem.LogService)
{
    Title = "Warnings & Errors",
    FilterLevel = LogLevel.Warning
};

window.AddControl(viewer);

Filtering by Category

// Only show entries logged under the "Window" category
var viewer = new LogViewerControl(windowSystem.LogService)
{
    Title = "Window Events",
    FilterCategory = "Window"
};

window.AddControl(viewer);

Writing to the Log

The control reflects whatever is written to its bound service. Use the ILogService convenience methods:

var log = windowSystem.LogService;

log.LogInfo("Application started", category: "System");
log.LogDebug("Loaded 42 items");
log.LogWarning("Cache nearly full", category: "Cache");

try
{
    DoWork();
}
catch (Exception ex)
{
    log.LogError("Work failed", ex, category: "Worker");
}

Never use Console.WriteLine in a SharpConsoleUI application โ€” it corrupts the UI. Route diagnostics through LogService and surface them with a LogViewerControl instead.

Logging From a Background Thread

The control is thread-safe, so it is fine to log from background work:

var viewer = new LogViewerControl(windowSystem.LogService) { Title = "Activity" };
window.AddControl(viewer);

_ = Task.Run(async () =>
{
    for (int i = 0; i < 100; i++)
    {
        windowSystem.LogService.LogInfo($"Processed batch {i}", category: "Worker");
        await Task.Delay(200);
    }
});

Entries logged from the background thread are queued and rendered on the next paint; with AutoScroll enabled the view follows the newest entry.

Adjusting the Retained Buffer

The number of entries retained (and therefore trimmed in the viewer) is governed by the service's MaxBufferSize:

windowSystem.LogService.MaxBufferSize = 1000; // keep the last 1000 entries

var viewer = new LogViewerControl(windowSystem.LogService) { Title = "Logs" };
window.AddControl(viewer);

Best Practices

  1. Bind to the system log service: Pass windowSystem.LogService so the viewer shows the library's own diagnostics alongside your messages.
  2. Filter for focus: Set FilterLevel (and optionally FilterCategory) to keep noisy logs readable.
  3. Use categories consistently: Logging with a category makes FilterCategory and visual grouping useful.
  4. Keep AutoScroll on for live tails: Leave AutoScroll = true so new entries stay visible; users scrolling up temporarily pauses the follow behavior.
  5. Tune MaxBufferSize: Adjust the service's MaxBufferSize to balance history depth against memory.
  6. Never write to the console: Route all diagnostics through LogService; console output corrupts the UI.

See Also

  • ListControl - For scrollable selectable lists
  • MarkupControl - For static markup-formatted text (used internally per entry)

Back to Controls | Back to Main Documentation