IrcChatControl.Wpf
0.7.0
dotnet add package IrcChatControl.Wpf --version 0.7.0
NuGet\Install-Package IrcChatControl.Wpf -Version 0.7.0
<PackageReference Include="IrcChatControl.Wpf" Version="0.7.0" />
<PackageVersion Include="IrcChatControl.Wpf" Version="0.7.0" />
<PackageReference Include="IrcChatControl.Wpf" />
paket add IrcChatControl.Wpf --version 0.7.0
#r "nuget: IrcChatControl.Wpf, 0.7.0"
#:package IrcChatControl.Wpf@0.7.0
#addin nuget:?package=IrcChatControl.Wpf&version=0.7.0
#tool nuget:?package=IrcChatControl.Wpf&version=0.7.0
IrcChatControl.Wpf
A high-throughput, console-style IRC chat control for WPF. Text is rendered by a native C++ DLL with Direct2D / DirectWrite into a D3D11 flip-model swapchain on a child HWND (hosted via HwndHost), bypassing WPF's retained-mode text stack entirely. A lock-free MPSC input queue and a fixed pre-allocated ring buffer let producer threads push thousands of lines per second without blocking the UI.
- Throughput: 1,000–5,000+ lines/sec sustained;
AddLineis thread-safe and cheap on the hot path. - Scrollback: 50,000-line pre-allocated ring buffer (configurable cap at runtime via
SetMaxLines). The renderer is persistent: when the control leaves the visual tree its surface is parked (hidden and reparented), not destroyed, so hosts that cache and Content-swap chat views keep their history — and switching back costs aSetParent+ShowWindow, with no replay, re-parse, or GPU recreation. - Formatting: mIRC control codes (bold, italic, underline, strikethrough, reverse, indexed colors incl. the extended 0–98 range,
\x04hex colors) and ANSI SGR escape sequences (ESC[...m, incl. 38/48 extended colors). - Unicode: full UTF-8 pipeline with emoji (color font) and CJK wide-cell support.
- Interaction: pixel-smooth wheel scrolling, PageUp/PageDown/Home/End, live scrollbar scrubbing, drag selection with clipboard copy, Ctrl+wheel font zoom.
- Idle cost: the render timer parks when nothing changes — 0% CPU at idle.
- Art-proof glyph atlas: monochrome glyphs are cached as color-independent alpha masks tinted at draw time, so rainbow-colored ASCII/Unicode art can't thrash the cache; atlas texture creation is additionally hard-capped per frame.
Requirements
- Windows 10/11, x64 only (see note below)
- .NET 8 (
net8.0-windows) - No VC++ redistributable needed — the native renderer links the CRT statically
x64 note: the native renderer ships only as a
win-x64binary. Set<PlatformTarget>x64</PlatformTarget>in your app project. On Windows ARM64 an AnyCPU .NET 8 app runs as a native arm64 process and will not load the x64 DLL (win-arm64does not fall back towin-x64in the RID graph); forcingPlatformTarget=x64makes the app run under x64 emulation instead, which works.
Install (NuGet)
dotnet add package IrcChatControl.Wpf
XAML:
<Window ...
xmlns:irc="https://github.com/spenny2012/sIRCChatWindow">
<irc:IrcChatControl x:Name="Chat" />
</Window>
(The clr-namespace form xmlns:irc="clr-namespace:IrcChatWpf;assembly=IrcChatControl.Wpf" works too.)
Code:
Chat.AddLine("\x0304Hello \x02world\x02 — colors, bold, ANSI \x1b[32mgreen\x1b[0m");
Use as a git submodule
git submodule add https://github.com/spenny2012/sIRCChatWindow.git external/sIRCChatWindow
- Add
src/IrcRendererNative/IrcRendererNative.vcxprojandsrc/IrcChatControl.Wpf/IrcChatControl.Wpf.csprojto your solution (the native project needs the VS "Desktop development with C++" workload + Windows 10/11 SDK). - Set a solution build dependency: IrcChatControl.Wpf → IrcRendererNative (the native DLL must exist before the library builds; you'll get a clear build warning if it doesn't).
- Reference
IrcChatControl.Wpffrom your app with aProjectReference. The native DLL flows to your output automatically.
The native project always writes to <submodule>/build/<Configuration>/ regardless of where your solution lives, and the library looks it up there — no path wiring needed.
API
| Member | Description |
|---|---|
AddLine(string text) |
Append a line (thread-safe). mIRC + ANSI codes parsed inline. Lines added while the control is unloaded are ingested immediately into the persistent scrollback. |
Clear() |
Empty the scrollback (also decommits the arena). |
LineCount |
Lines currently held in the ring buffer. |
ScrollToEnd() |
Jump to the newest line and re-pin auto-follow. |
SetMaxLines(int) |
Cap the scrollback line count at runtime. |
WrapExtendedColors |
Classic-client color compatibility (default true): inbound \x03 indices 16–98 fold onto the basic palette (mod 16) instead of the standardized extended palette. |
ParkedViewLimit (static) |
How many hidden controls keep their GPU surface parked for instant reattach (default 2). Hidden controls beyond the limit release their surface — scrollback is unaffected — and rebuild in a few ms when shown again. |
Dispose() |
Deterministically frees the native renderer (scrollback + GPU) when a chat window closes for good; otherwise the SafeHandle finalizer frees it eventually. |
TrimMemory() / TrimAllMemory() (static) |
Returns committed scrollback memory no longer in use to the OS (native arena compaction + decommit; content intact). Hook TrimAllMemory into an idle timer. |
Background / Foreground / SelectionBrush |
Standard WPF brush properties — bindable, stylable, DynamicResource-friendly. Solid brushes reach the renderer. |
FontFamily / FontSize |
Standard WPF font properties (default Consolas 14); inherit from the host window like any control. |
SetBackgroundColor(Color) / SetForegroundColor(Color) / SetSelectionColor(Color) / SetFontFamily(string) / SetFontSize(double) |
Method equivalents of the properties above for code-driven theming. |
EnableFontZoom |
Enable/disable Ctrl+wheel zoom (default on, clamped 6–72 pt). |
CurrentFontSize |
The effective font size after zooming (same value as FontSize). |
Keyboard scrolling (PageUp/PageDown/Home/End) activates after the control has been clicked (it takes focus on mouse-down).
Theming
The control themes like any WPF control — bind or style the standard properties:
<irc:IrcChatControl Background="{DynamicResource ChatBackgroundBrush}"
Foreground="{DynamicResource ChatForegroundBrush}"
FontFamily="Cascadia Mono" FontSize="13" />
Only SolidColorBrush values are forwarded to the native renderer (gradients/images can't be, and are applied to the WPF chrome only). FontFamily/FontSize are inherited properties, so a window-wide font cascades into the control; unstyled controls keep the console default (Consolas 14 on a dark palette). Theme changes are push-on-change only — nothing on the AddLine/render hot path reads these properties.
Formatting codes
| Code | Meaning |
|---|---|
\x02 |
Toggle bold |
\x03 |
mIRC color index 0–98, optional ,background (99 = default fg; bare resets fg and bg). Indices 16–98 fold mod-16 by default (WrapExtendedColors) |
\x04 |
Hex color RRGGBB, optional ,RRGGBB background (bare = default) |
\x0F |
Reset all formatting |
\x16 |
Toggle reverse video (swap fg/bg) |
\x1D |
Toggle italic |
\x1E |
Toggle strikethrough |
\x1F |
Toggle underline |
\x1B[...m |
ANSI SGR: styles (1/3/4/7/9…), 16/256/truecolor via 38/48 |
\x01, \x11 |
Stripped (CTCP delimiter; monospace toggle — layout is always monospace) |
Building from source
# 1. Native renderer (needs VS 2022 C++ workload + Windows SDK)
msbuild src\IrcRendererNative\IrcRendererNative.vcxproj -p:Configuration=Release -p:Platform=x64
# 2. Demo app (also builds the library)
dotnet build demo\IrcChatWpf\IrcChatWpf.csproj -c Release -p:Platform=x64
# Run the spam-test harness
demo\IrcChatWpf\bin\x64\Release\net8.0-windows\win-x64\IrcChatWpf.exe
Or open IrcChat.sln in Visual Studio 2022 (Release | x64) — build order is wired in the solution.
The demo harness generates random formatted lines at a configurable rate (default 2,000/sec) with buttons for theming, font cycling, scrollback capping, and a test pattern.
Architecture
IrcChat.sln
├── src/IrcRendererNative/ C++ native DLL (Direct2D/DirectWrite/D3D11)
│ ├── RingBuffer.h/cpp Fixed-capacity line ring buffer (arena-backed)
│ ├── MpscQueue.h Lock-free multi-producer/single-consumer queue
│ ├── IrcParser.h/cpp Inline mIRC + ANSI SGR parser
│ ├── TextCells.h Emoji/CJK cell model
│ └── Renderer.h/cpp Flip-model swapchain, D2D/DWrite rendering
├── src/IrcChatControl.Wpf/ .NET 8 WPF class library (the NuGet package)
│ ├── NativeMethods.cs P/Invoke layer
│ ├── IrcSwapchainHost.cs HwndHost hosting the renderer's child HWND
│ └── IrcChatControl.xaml/.cs Public UserControl + scrollbar/input handling
└── demo/IrcChatWpf/ Spam-test harness (WinExe)
AddLineUTF-8-encodes straight into the lock-free queue; the render pass drains it into pre-allocated ring-buffer slots — nostd::string, no heap allocation, no exceptions on the hot path.- Only visible lines are drawn. A ~60 Hz
DispatcherTimerdrives frames and parks itself when idle (a wake protocol on the producer side restarts it), so an idle window costs zero CPU. - Word-wrap is column arithmetic against the monospace grid; each slot caches its wrapped row count and resizes re-wrap in one pass (deferred while zooming).
- Rendering goes to a DXGI flip-model swapchain on a child HWND — no D3D9 interop, no
D3DImage, no per-frame GPU copies through WPF.
Host-app memory tuning (optional)
The demo's App.xaml.cs shows two optional, app-level optimizations that meaningfully shrink a chat-centric app's footprint; both are choices for your application, not behavior of the control:
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly— keeps WPF itself off the GPU. The chat surface has its own swapchain, so WPF hardware acceleration would only composite chrome, at the cost of a D3D9Ex device and vendor driver stack (~tens of MB). Set it before the first window is created; skip it if your app has GPU-heavy WPF UI of its own.- A settle-then-trim pattern (aggressive Gen2 collect +
SetProcessWorkingSetSizeonce at startup and again after activity bursts go quiet) — startup XAML parsing and message floods leave garbage in committed GC regions that steady state never touches.
Tuning constants
| Constant | Location | Effect |
|---|---|---|
IrcLineCapacity |
RingBuffer.h |
Compile-time scrollback capacity (50,000). |
IrcLineTextSize |
RingBuffer.h |
Max bytes per line (512). |
IrcMaxSegments |
RingBuffer.h |
Max color/format runs per line (255 — enough for per-character colored ASCII art; storage packs by actual count). |
InputQueueCapacity |
Renderer.h |
Lock-free queue depth (power of two). |
MaxInputBatch |
Renderer.cpp |
Lines drained per frame; raise for >15k lines/sec. |
| Timer interval | IrcSwapchainHost.cs |
~16 ms (60 FPS); parks at idle. |
License
GPL-3.0-or-later — see LICENSE. Note the copyleft implication: if you distribute an application that includes this control, the GPL's terms apply to that distribution. (© the repository owner; other arrangements are possible on request.)
| 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
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.0 | 41 | 7/20/2026 |