TinyChat.DevExpress
2.2.9
See the version list below for details.
dotnet add package TinyChat.DevExpress --version 2.2.9
NuGet\Install-Package TinyChat.DevExpress -Version 2.2.9
<PackageReference Include="TinyChat.DevExpress" Version="2.2.9" />
<PackageVersion Include="TinyChat.DevExpress" Version="2.2.9" />
<PackageReference Include="TinyChat.DevExpress" />
paket add TinyChat.DevExpress --version 2.2.9
#r "nuget: TinyChat.DevExpress, 2.2.9"
#:package TinyChat.DevExpress@2.2.9
#addin nuget:?package=TinyChat.DevExpress&version=2.2.9
#tool nuget:?package=TinyChat.DevExpress&version=2.2.9
TinyChat 💬
A minimalistic but extensible chat control library for Windows Forms.
✨ Features
- Two control suites: vendor-control-free Windows Forms controls in
TinyChatand a skinnable DevExpress implementation inTinyChat.DevExpress - Streaming support: real-time message streaming for AI assistants and live conversations
- Microsoft.Extensions.AI integration: use any registered
IChatClient, including keyed services, with streaming, cancellation, chat options, reasoning, and function calls - File and image attachments: add files through drag and drop, clipboard paste, or the public API; images are shown as previews
- Selectable and copyable content: directly select regular message text, function-call arguments and results, or reasoning details and copy it with standard keyboard shortcuts
- Designer-friendly appearance: configure fonts, colors, history, message and input spacing, welcome alignment, the splitter, and behavioral options in the Windows Forms Designer
- New-chat lifecycle: cancel the active response and clear the conversation and input draft in one call
- Readable message rendering: native controls use cleaned plain text, while the DevExpress suite keeps its safe HTML/CSS formatting in a permanently selectable message surface
- Extensible architecture: interface-driven design and factory methods for custom message types and UI components
Control suites
| NuGet package | Control | UI components | Default formatter |
|---|---|---|---|
TinyChat |
ChatControl |
Native Windows Forms controls | PlainTextMessageFormatter |
TinyChat.DevExpress |
DXChatControl |
DevExpress controls | SimplifiedHtmlMessageFormatter (selectable HTML/CSS body view) |
Both controls share the same public chat API. DXChatControl derives from ChatControl and replaces the primary editors, message controls, history, welcome surface, and splitter with DevExpress counterparts.
TinyChat.DevExpress is built and tested with DevExpress 24.2.12 and requires the corresponding DevExpress license.
💖 Motivation
While there are countless web-based chat controls, there are very few for the good old Windows Forms ecosystem. TinyChat provides a focused user interface for interacting with AI models inside an existing WinForms application.
DevExpress also offers a feature-rich AI Chat Control. It is based on web technologies and therefore adds a significant set of deployment dependencies. TinyChat deliberately stays smaller and exposes factory methods and interfaces for applications that need to customize it.
Known limitations
- Full formatting specifications are not implemented. Native Windows Forms message controls display cleaned plain text. The DevExpress controls support a practical subset of common HTML and Markdown constructs, but not every HTML, Markdown, or RTF feature an assistant may emit.
- Image rendering currently focuses on attachments. Local or pasted images have previews and are sent to compatible
IChatClientimplementations as multimodal content. Arbitrary remote images or image content returned by an assistant are not rendered automatically. - Provider capabilities still apply. A provider or model may reject a binary attachment format even though TinyChat can load and forward it. Override
ConvertFileAttachment()when files need extraction, upload, or RAG processing first.
🚀 Quick start
Native Windows Forms
using TinyChat;
var chatControl = new ChatControl
{
Dock = DockStyle.Fill
};
Controls.Add(chatControl);
For the DevExpress suite, reference TinyChat.DevExpress and instantiate DXChatControl instead. The remaining API is the same.
Basic message handling
The Messages property supplies an existing conversation. MessageSending can inspect or cancel a user message, while MessageSent runs after it was accepted.
chatControl.MessageSent += (_, e) =>
{
Console.WriteLine($"User sent: {e.Content}");
chatControl.AddMessage(
new NamedSender("Assistant"),
new StringMessageContent("Hello! How can I help you?"));
};
Starting a new chat
Use StartNewChat() instead of assigning an empty message collection. It requests cancellation of an active response and clears the built-in conversation, text draft, pending attachments, and selection in one call.
chatControl.NewChatStarted += (_, _) =>
{
// Reset any application-specific session state here.
};
chatControl.StartNewChat();
Custom input controls can implement IChatInputDraftControl so their own draft state is cleared by the same call.
Designer and appearance settings
The following properties are available in the Windows Forms Designer and work for both control suites:
chatControl.MessageFont = new Font("Segoe UI", 10f);
chatControl.InputFont = new Font("Segoe UI", 10f);
chatControl.InputEditorBackColor = Color.Empty; // native/skin default
chatControl.InputEditorForeColor = Color.Empty; // native/skin default
chatControl.InputEditorBorderStyle = BorderStyle.Fixed3D;
chatControl.InputPlaceholderText = "Ask TinyChat";
chatControl.WelcomeFont = new Font("Segoe UI", 14f);
chatControl.WelcomeMessage = "How can I help?";
chatControl.HistoryPadding = new Padding(12);
chatControl.MessagePadding = new Padding(10);
chatControl.MessageMargin = new Padding(4);
chatControl.InputPadding = new Padding(10);
chatControl.WelcomeTextAlign = ContentAlignment.MiddleCenter;
chatControl.IsSplitterFixed = true;
chatControl.SplitterPosition = 90;
chatControl.AllowExpandFunctionCalls = true;
chatControl.AllowExpandReasoning = true;
chatControl.IncludeFunctionCalls = false;
chatControl.IncludeReasoning = false;
chatControl.AssistantSenderName = "AI Assistant";
Font, ForeColor, and BackColor provide the global appearance for the chat surface and are propagated by both the native Windows Forms and DevExpress suites. The editable input surface deliberately keeps its native Windows or active DevExpress skin colours so that it remains visually distinct and does not look read-only. Set InputEditorBackColor or InputEditorForeColor to override those defaults; reset either property to Color.Empty to resume platform/skin rendering. MessageFont and InputFont inherit from Font until explicitly changed; resetting them resumes that inheritance. WelcomeFont is independent, and resetting it restores the larger default welcome font.
The layout and input appearance properties have the same meaning and defaults in both suites:
| Property | Scope | Default after reset |
|---|---|---|
HistoryPadding |
Padding inside the history area, including the welcome surface | 0 on every side |
MessagePadding |
Inner padding of regular, function-call, and reasoning messages | 8 on every side |
MessageMargin |
Outer margin of every message | 3 on every side |
InputPadding |
Inner padding of the complete input area | 8 on every side |
InputEditorBackColor |
Background of the editable text surface | Color.Empty (platform/skin default) |
InputEditorForeColor |
Text colour of the editable text surface | Color.Empty (platform/skin default) |
InputEditorBorderStyle |
Native border or mapped DevExpress skin border | BorderStyle.Fixed3D |
InputPlaceholderText |
Prompt shown while the input is empty | Empty |
WelcomeTextAlign |
Alignment of the welcome text within the history area | ContentAlignment.MiddleCenter |
IsSplitterFixed |
Prevents the user from moving the splitter when enabled | false |
SplitterPosition |
Height of the lower input area in pixels | 60 |
AllowExpandFunctionCalls |
Allows function-call details to be expanded | true |
AllowExpandReasoning |
Allows reasoning details to be expanded | true |
IncludeFunctionCalls |
Shows function calls captured from IChatClient responses |
false |
IncludeReasoning |
Shows reasoning captured from IChatClient responses |
false |
AssistantSenderName |
Name shown for automatic IChatClient responses |
Assistant |
Resetting one of these properties in the Designer restores the listed value. The inherited ChatControl.Padding property remains the outer padding around the combined chat surface; it is not inherited by the history, messages, or input area.
These settings also apply retrospectively. Changing the assistant name, formatter, content filters, or expand permissions updates the existing message controls in place instead of rebuilding the history. Hidden function calls and reasoning continue to be captured, so enabling their filters later reveals the original controls without interrupting active streaming. Hiding a selected message intentionally clears that selection. Messages added explicitly through AddMessage keep their own sender identity and remain visible independently of the IChatClient visualization filters.
Selecting and copying text
Both control suites display regular message bodies permanently in selectable text views. Drag directly over the required text and press <kbd>Ctrl</kbd>+<kbd>C</kbd>; no renderer or selection-mode switch is required. Starting a selection in another message clears the previous selection, so multiple message bodies are never highlighted at the same time.
Function-call arguments and results as well as reasoning details are directly selectable in the same way. You can also click the sender/header or message background and press <kbd>Ctrl</kbd>+<kbd>C</kbd> to copy the complete message.
File and image attachments
When AllowFileAttachments is enabled (the default), users can:
- drop files anywhere on the chat;
- paste copied files or a bitmap into the input;
- remove attachments from the draft before sending;
- see small image previews and document tiles.
The default per-file limit is 20 MiB and can be changed with MaximumAttachmentFileSize. Files can also be supplied in code:
await chatControl.AddFilesToInputAsync(openFileDialog.FileNames);
await chatControl.SendFilesAsync(
["report.pdf", "diagram.png"],
"Summarize these files.");
Text attachments are forwarded as named text sections. Images and other binary files are represented as typed DataContent for Microsoft.Extensions.AI.
Streaming messages with IAsyncEnumerable
Pass a token stream to AddStreamingMessage(). TinyChat marshals display updates back to the UI synchronization context.
IAsyncEnumerable<string> stream = GetTokenStream();
chatControl.AddStreamingMessage(new NamedSender("AI Assistant"), stream);
Using IChatClient with dependency injection
TinyChat can resolve and call a Microsoft.Extensions.AI.IChatClient automatically.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using TinyChat;
var services = new ServiceCollection();
services.AddSingleton<IChatClient>(CreateChatClient());
var chatControl = new ChatControl
{
ServiceProvider = services.BuildServiceProvider(),
UseStreaming = true,
AssistantSenderName = "AI Assistant"
};
The complete conversation is converted and passed to the client. Override ConvertToChatMessages() or DetermineChatRole() when the default sender-to-role mapping does not fit your application. ChatOptions and ChatOptionsRequested customize each request; IncludeFunctionCalls and IncludeReasoning control whether the corresponding captured response details are visible.
Keyed clients are supported as well:
services.AddKeyedSingleton<IChatClient>("basic", CreateBasicClient());
services.AddKeyedSingleton<IChatClient>("premium", CreatePremiumClient());
chatControl.ChatClientServiceKey = "premium";
Formatting
Both suites use a permanently visible message surface so that text can always be selected without changing renderers. ChatControl uses a read-only native TextBox and PlainTextMessageFormatter to remove common HTML and Markdown syntax while keeping the text readable.
DXChatControl uses a permanent DevExpress HtmlContentControl. It combines formatted rendering with native DevExpress text selection, automatic height calculation, and stable streaming updates in the same control. SimplifiedHtmlMessageFormatter remains the default; its supported bold, italic, underline, strike-through, heading, color, code-font, paragraph, line-break, and link output is converted to a safe HTML/CSS-template subset before rendering. Remote images and unsafe link schemes are not injected into message templates.
Both suites preserve Unicode emoji, including multi-code-point sequences. Their exact colour and glyph style still depend on the installed Windows fonts and the active renderer; native Windows Forms commonly displays monochrome glyphs.
Function-call arguments and results as well as reasoning details use the same selectable DevExpress HTML surface, with their plain text HTML-encoded before display.
To customize normalization and rendering, implement IMessageFormatter and override CreateDefaultMessageFormatter().
🎬 Demos
DemoApp contains both native Windows Forms and DevExpress examples, including direct IChatClient integration:
dotnet run --project DemoApp
Credits
The package icon was made by Vectors Market and is licensed under the Flaticon license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0-windows7.0 is compatible. net10.0-windows was computed. net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- DevExpress.Win (>= 24.2.12)
- TinyChat (>= 2.2.9)
-
net9.0-windows7.0
- DevExpress.Win (>= 24.2.12)
- TinyChat (>= 2.2.9)
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 |
|---|---|---|
| 2.2.11 | 37 | 10/27/2026 |
| 2.2.10 | 37 | 10/27/2026 |
| 2.2.9 | 87 | 10/26/2026 |
| 2.2.8 | 225 | 7/15/2026 |
| 2.2.7 | 135 | 6/12/2026 |
| 2.2.6 | 137 | 5/5/2026 |
| 2.2.5 | 133 | 4/23/2026 |
| 2.2.4 | 149 | 4/7/2026 |
| 2.2.3 | 133 | 4/7/2026 |
| 2.2.2 | 136 | 3/26/2026 |
| 2.2.1 | 124 | 3/20/2026 |
| 2.1.7 | 127 | 3/20/2026 |
| 2.1.6 | 134 | 3/20/2026 |
| 2.1.5 | 148 | 3/4/2026 |
| 2.1.4 | 138 | 3/2/2026 |
| 2.1.3 | 138 | 3/2/2026 |
| 2.1.2 | 146 | 3/2/2026 |
| 2.1.1 | 144 | 2/26/2026 |
| 2.0.10 | 148 | 2/24/2026 |
| 2.0.9 | 142 | 2/24/2026 |