Back to Devexpress

AI Chat Control

windowsforms-405218-ai-powered-extensions-ai-chat-control.md

latest22.3 KB
Original Source

AI Chat Control

  • Jan 21, 2026
  • 11 minutes to read

Note

The DevExpress AI Chat Control (AIChatControl) can only be used in Windows Forms applications that target the .NET 8+ framework.

The AI Chat Control (AIChatControl) allows you to incorporate an interactive, Copilot-inspired chat-based UI within your WinForms application. This control leverages BlazorWebView to reuse the DevExpress Blazor AI Chat component (DxAIChat).

View Example: AI Chat

Tip

The following example extends the DevExpress WinForms Chat Client App demo. It creates a Copilot-inspired, AI-powered chat interface without using BlazorWebView. The example uses ‘native’ DevExpress UI controls (such as the GridControl, MemoEdit, and HtmlContentControl). The app targets .NET Framework 4.6.2 or later and integrates with the Azure OpenAI service to support conversational engagement, Markdown rendering, and structured message display within a fully native WinForms environment.

View Example: WinForms Chat for .NET Framework

Getting Started

Install DevExpress NuGet Packages

  1. DevExpress.AIIntegration.WinForms.Chat
  2. DevExpress.Win.Design (enables design-time features for DevExpress UI controls)

Change Project SDK

Update the project SDK to Microsoft.NET.Sdk.Razor:

<Project Sdk="Microsoft.NET.Sdk.Razor">

Register AI Client

See the following help topic for information on required NuGet packages and system requirements: Register an AI Client.

The following code snippet registers the Azure OpenAI client:

csharp
using Microsoft.Extensions.AI;
using DevExpress.AIIntegration;

internal static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        IChatClient azureChatClient = new Azure.AI.OpenAI.AzureOpenAIClient(new Uri(AzureOpenAIEndpoint),
            new System.ClientModel.ApiKeyCredential(AzureOpenAIKey))
            .GetChatClient(ModelId).AsIChatClient();
        AIExtensionsContainerDesktop.Default.RegisterChatClient(azureChatClient);
        Application.Run(new Form1());
    }
    static string AzureOpenAIEndpoint { get { return Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); } }
    static string AzureOpenAIKey { get { return Environment.GetEnvironmentVariable("AZURE_OPENAI_APIKEY"); } }
    static string ModelId { get { return "gpt-4o-mini"; } }
}
vb
Imports Microsoft.Extensions.AI
Imports DevExpress.AIIntegration

Friend Module Program
    <STAThread>
    Sub Main()
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        ' Register Azure.OpenAI
        Dim azureChatClient As IChatClient = New Azure.AI.OpenAI.AzureOpenAIClient(New Uri(AzureOpenAIEndpoint),
            New System.ClientModel.ApiKeyCredential(AzureOpenAIKey)).
            GetChatClient(ModelId).AsIChatClient()
        AIExtensionsContainerDesktop.Default.RegisterChatClient(azureChatClient)
        Application.Run(New Form1())
    End Sub
    Private ReadOnly Property AzureOpenAIEndpoint() As String
        Get
            Return Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
        End Get
    End Property
    Private ReadOnly Property AzureOpenAIKey() As String
        Get
            Return Environment.GetEnvironmentVariable("AZURE_OPENAI_APIKEY")
        End Get
    End Property
    Private ReadOnly Property ModelId As String
        Get
            Return "gpt-4o-mini"
        End Get
    End Property
End Module

Create AI Chat Control

Drop the AIChatControl from the toolbox onto a Form.

Note

The AI Chat Control does not support design-time rendering.

The following code snippet creates the AIChatControl with default settings:

csharp
using DevExpress.AIIntegration.WinForms.Chat;

public partial class Chat : XtraForm {
    public Chat() {
        InitializeComponent();

        AIChatControl chat = new AIChatControl(){
            Name = "aiChatControl1",
            Dock = DockStyle.Fill
        };
        this.Controls.Add(chat);
    }
}
vb
Imports DevExpress.AIIntegration.WinForms.Chat

Partial Public Class Chat
    Inherits XtraForm

    Public Sub New()
        InitializeComponent()

        Dim chat As New AIChatControl() With {
            .Name = "aiChatControl1",
            .Dock = DockStyle.Fill
        }
        Me.Controls.Add(chat)
    End Sub
End Class

AI Chat Project Templates

Use the following AI Chat project templates to create a chat application that integrates the AI Chat Control:

AI Chat ApplicationCreates a WinForms chat app that integrates the AI Chat Control.AI Chat (RAG) ApplicationCreates a desktop WinForms application with the AI Chat Control and built-in Retrieval-Augmented Generation (RAG) for document-grounded conversations.

Both templates support .NET 8 / .NET 9 and integrate the DevExpress MCP Server for DevExpress-specific guidance.

See the following help topic for more information: AI Chat Project Templates.

Streaming

The AI Chat Control can display responses from the AI assistant as they are generated in a natural, conversational flow (rather than waiting for the entire message to complete before showing it to the user). Enable the UseStreaming setting to activate streaming:

csharp
aiChatControl1.UseStreaming = DevExpress.Utils.DefaultBoolean.True;
vb
aiChatControl1.UseStreaming = DevExpress.Utils.DefaultBoolean.True

Play the following animation to see the result:

Markdown Message Rendering

  • Set the ContentFormat property to Markdown to receive responses as Markdown.
  • Handle the MarkdownConvert event to convert Markdown text into HTML and make responses more readable, structured, and visually appealing.

Warning

Always sanitize AI-generated content before rendering it in the UI.

The following example enables Markdown message rendering. The example uses the Markdig Markdown processing library to convert Markdown text into HTML.

csharp
using DevExpress.AIIntegration.Blazor.Chat;
using DevExpress.AIIntegration.Blazor.Chat.WebView;
using Ganss.Xss;
using Markdig;

var sanitizer;

public Chat() {
    InitializeComponent();
    sanitizer = new HtmlSanitizer();
    aiChatControl1.ContentFormat = ResponseContentFormat.Markdown
    aiChatControl1.MarkdownConvert += AiChatControl1_MarkdownConvert
}

void AiChatControl1_MarkdownConvert(object sender, AIChatControlMarkdownConvertEventArgs e) {
    // Convert Markdown to HTML.
    string html = Markdown.ToHtml(e.MarkdownText);

    // WARNING: The AI agent's content may be untrusted. 
    // Developers must sanitize all HTML before rendering to prevent XSS attacks.
    string safeHtml = sanitizer.Sanitize(html);

    // Assign sanitized HTML for rendering.
    e.HtmlText = (MarkupString)safeHtml;
}
vb
Imports DevExpress.AIIntegration.Blazor.Chat
Imports DevExpress.AIIntegration.Blazor.Chat.WebView
Imports Ganss.Xss
Imports Markdig

Public Class Chat
    Private sanitizer As HtmlSanitizer

    Public Sub New()
        InitializeComponent()
        sanitizer = New HtmlSanitizer()
        aiChatControl1.ContentFormat = ResponseContentFormat.Markdown
        AddHandler aiChatControl1.MarkdownConvert, AddressOf AiChatControl1_MarkdownConvert
    End Sub

    Private Sub AiChatControl1_MarkdownConvert(sender As Object, e As AIChatControlMarkdownConvertEventArgs)
        ' Convert Markdown to HTML.
        Dim html As String = Markdown.ToHtml(e.MarkdownText)

        ' WARNING: The AI agent's content may be untrusted. 
        ' Developers must sanitize all HTML before rendering to prevent XSS attacks.
        Dim safeHtml As String = sanitizer.Sanitize(html)

        ' Assign sanitized HTML for rendering
        e.HtmlText = DirectCast(safeHtml, Microsoft.AspNetCore.Components.MarkupString)
    End Sub
End Class

The following screenshot shows the result:

File Attachments

Users can now attach files directly to their chat messages. The AI analyzes document content (such as text files, PDFs, images) and delivers more context-aware responses.

To activate file upload:

  1. Enable the FileUploadEnabled property to allow users to attach files.

  2. Configure additional settings based on your project requirements (the maximum file size, allowed file types/extensions, the maximum number of files that users can attach to a message):

Tip

See the following article for more information on MIME types (FileTypeFilter): Common Media Types.

Prompt Suggestions

To help users get started or explore new possibilities, the DevExpress AI Chat Control can display prompt suggestions.

Use the SetPromptSuggestions method to supply relevant prompts:

csharp
using DevExpress.AIIntegration.Blazor.Chat.WebView;

aiChatControl1.SetPromptSuggestions(new List<PromptSuggestion>(){
    new PromptSuggestion(
        title: "Birthday Wish",
        text: "A warm and cheerful birthday greeting message.",
        prompt: "Write a heartfelt birthday message for a close friend."),

    new PromptSuggestion(
        "Thank You Note",
        "A polite thank you note to express gratitude.",
        "Compose a short thank you note to a colleague who helped with a project.")
});

The AI Chat Control automatically inserts a selected prompt suggestion into the chat prompt box so users can edit it before sending. Activate the PromptSuggestion.SendOnClick option to send a prompt suggestion to the AI service immediately after it is clicked.

Customize Empty Text

Use the EmptyStateText property to specify the message displayed when a chat has yet to start:

csharp
aiChatControl1.EmptyStateText = "AI Assistant is ready to answer your questions.";
vb
aiChatControl1.EmptyStateText = "AI Assistant is ready to answer your questions."

The following screenshot shows the result:

Customize Chat UI and Appearance

The AIChatControl supports appearance customization through Razor-based templates. You can customize chat messages, prompt suggestions, and the text displayed when the chat has no message history.

Message Templates

Use the following methods to customize chat message container (including paddings and inner content alignment) and content:

  • SetMessageTemplate(RenderFragment<BlazorChatMessage> template)
  • SetMessageContentTemplate(RenderFragment<BlazorChatMessage> template)

Note

The Message Template property takes priority over the Message Content Template if both templates are specified.

The following example displays a custom button within chat messages. When a user clicks the button, a message box appears.

csharp
using DevExpress.XtraEditors;
using Microsoft.AspNetCore.Components;
using using DevExpress.AIIntegration.Blazor.Chat;

public Form1() {
    InitializeComponent();

    aiChatControl1.SetMessageTemplate(message => builder => {
        builder.OpenComponent<Message>(0);
        builder.AddAttribute(1, "message", message);
        builder.AddAttribute(2, "OnButtonClick", EventCallback.Factory.Create<BlazorChatMessage>(this, CustomButtonClick));
        builder.CloseComponent();
    });
}

void CustomButtonClick(BlazorChatMessage message) {
    XtraMessageBox.Show($"Message: {message.Content}");
}

The Message.razor file:

razor
@using Microsoft.AspNetCore.Components.Web
@using DevExpress.AIIntegration.Blazor.Chat

<style>
    .my-custom-button {
        background-color: #007acc;
        color: white;
        border: none;
        padding: 6px 12px;
        border-radius: 4px;
        cursor: pointer;
    }

        .my-custom-button:hover {
            background-color: #005fa3;
        }
</style>

<div class="@GetMessageClasses(message)">
    @if (message.Typing) {
        <span>Loading...</span>
    }
    else {
        <div class="demo-chat-content">
            @message.Content
            <button class="my-custom-button" @onclick="OnButtonClicked">Click me</button>
        </div>
    }
</div>

@code {
    [Parameter]
    public BlazorChatMessage message { get; set; }

    [Parameter]
    public EventCallback<BlazorChatMessage> OnButtonClick { get; set; }

    string GetMessageClasses(BlazorChatMessage message) {
        switch (message.Role) {
            case ChatMessageRole.Assistant:
                return "dxbl-chatui-message dxbl-chatui-message-assistant";
            case ChatMessageRole.User:
                return "dxbl-chatui-message dxbl-chatui-message-user";
            case ChatMessageRole.Error:
                return "dxbl-chatui-message dxbl-chatui-message-error";
            default:
                return "dxbl-chatui-message";
        }
    }

    async Task OnButtonClicked() {
        if (OnButtonClick.HasDelegate)
            await OnButtonClick.InvokeAsync(message);
    }
}

Prompt Suggestion Template

Use the SetPromptSuggestionContentTemplate(RenderFragment<IPromptSuggestion> template) method to customize prompt suggestions.

Empty Message Area Template

Use the SetEmptyMessageAreaTemplate(RenderFragment template) method to customize the UI when the chat has no message history.

csharp
aiChatControl1.SetEmptyMessageAreaTemplate(builder => {
    builder.OpenComponent<EmptyArea>(0);
    builder.CloseComponent();
});

The EmptyArea.razor file:

razor
<style>
    .demo-chat-ui-description {
        font-weight: bold;
        font-size: 20px;
        text-align: center;
    }
</style>

<div class="demo-chat-ui-description">
    AI Assistant is ready to answer your questions.
</div>

Title and Clear Chat Button

The AIChatControl can display the header. The header contains a customizable chat title and a Clear Chat button (removes all messages from the conversation history except system messages).

Use the AIChatControl.ShowHeader option to display the chat header. The AIChatControl.HeaderText property specifies the chat title.

csharp
aiChatControl1.ShowHeader = DevExpress.Utils.DefaultBoolean.True;
aiChatControl1.HeaderText = "AI Assistant";

Resize Input Area

Enable the AIChatControl.AllowResizeInput option to allow users resize the input area. Users can drag the top edge up to enlarge the input area or down to display a more detailed chat history.

csharp
aiChatControl1.AllowInputResize = DevExpress.Utils.DefaultBoolean.True;

Handle Chat Messages

To manually process messages sent to an AI service, handle the MessageSent event. For example, you can manually call the AI client or service of choice and return its responses to the chat. The following example adds responses to user questions:

csharp
using DevExpress.AIIntegration.Blazor.Chat.WebView;
using Microsoft.Extensions.AI;

public Chat() {
    InitializeComponent();
    aiChatControl1.MessageSent += AiChatControl1_MessageSent;
}

async void AiChatControl1_MessageSent(object sender, AIChatControlMessageSentEventArgs e) {
    await e.SendMessage($"Processed: {e.Content}", ChatRole.Assistant);
}
vb
Imports DevExpress.AIIntegration.Blazor.Chat.WebView
Imports Microsoft.Extensions.AI

Public Sub New()
    InitializeComponent()
    AddHandler aiChatControl1.MessageSent, AddressOf AiChatControl1_MessageSent
End Sub

Async Sub AiChatControl1_MessageSent(ByVal sender As Object, ByVal e As AIChatControlMessageSentEventArgs)
    Await e.SendMessage($"Processed: {e.Content}", ChatRole.Assistant)
End Sub

Save and Load Chat History

Use the following methods to manage chat history:

  • SaveMessages – Returns an IEnumerable<ChatMessage> collection of messages.
  • LoadMessages – Loads messages from the specified IEnumerable<ChatMessage> collection to the AI Chat Control and refreshes the control.

The following example saves/loads chat history when the user clicks the Save/Load button:

csharp
public partial class Chat : XtraForm {
    List<BlazorChatMessage> chatHistory;
    public Chat() {
        InitializeComponent();
        buttonSave.Click += ButtonSave_Click;
        buttonLoad.Click += ButtonLoad_Click;
    }

    void ButtonSave_Click(object sender, EventArgs e) {
        chatHistory = (List<BlazorChatMessage>)aiChatControl1.SaveMessages();
    }

    void ButtonLoad_Click(object sender, EventArgs e) {
        if(chatHistory != null)
            aiChatControl1.LoadMessages(chatHistory);
    }
}
vb
Partial Public Class Chat
    Inherits XtraForm

    Private chatHistory As List(Of BlazorChatMessage)
    Public Sub New()
        InitializeComponent()
        AddHandler buttonSave.Click, AddressOf ButtonSave_Click
        AddHandler buttonLoad.Click, AddressOf ButtonLoad_Click
    End Sub

    Private Sub ButtonSave_Click(ByVal sender As Object, ByVal e As EventArgs)
        chatHistory = CType(aiChatControl1.SaveMessages(), List(Of BlazorChatMessage))
    End Sub

    Private Sub ButtonLoad_Click(ByVal sender As Object, ByVal e As EventArgs)
        aiChatControl1.LoadMessages(chatHistory)
    End Sub
End Class

Resources

The AIChatControl can access external or dynamically generated data through resources. A resource is an instance of the AIChatResource class that supplies text or binary content to the AI model at request time.

Resources extend the chat context with additional input (for example, local documents, logs, or images). The AI model uses this data to generate more accurate and context-aware responses.

After you assign resources, the AIChatControl displays the “Attach Context” (+) button. Users can select one or more resources to include in the chat request.

See the following help topic for more information: Resources.

Create an Assistant That Chats Using Your Own Data

When integrating the AI Chat Control with the OpenAI Assistant API, you can configure it to retain and reference a specific context (for example, a text file or a PDF document). By providing a supplementary document as a context source, the assistant is primed with background information. OpenAI automatically parses the document and searches through it to retrieve relevant content to better respond to user queries.

See the following help topic for more information: Chat with Your Own Data.

Manage Multiple Chat Client Services

The WinForms AIChatControl supports multiple AI services in a single application, which enables you to:

  • Run several independent chat UIs side by side powered by different AI services.
  • Use one chat UI and dynamically switch between AI services or AI agents.

See the following help topic for more information: Manage Multiple Chat Clients.

Troubleshooting

Deploy to Windows Server

When deploying WinForms applications with the AI Chat Control to Windows Server or earlier versions of Windows, you may encounter the following error:

Warning

Microsoft.Web.WebView2.Core.WebView2RuntimeNotFoundException : ‘Could not find a compatible WebView2 Runtime installation to host WebViews.’

The WinForms AI Chat Control leverages BlazorWebView to reuse the DevExpress Blazor DxAIChat component. This integration requires the WebView2 runtime to be installed on the target machine.

Windows 11 includes WebView2. However, earlier versions of Windows and Windows Server may not have it pre-installed. To ensure compatibility, refer to the following help topic for information on distributing the WebView2 runtime with your WinForms application to operating systems other than Windows 11: Distribute your app and the WebView2 Runtime.

See Also

DevExpress AI-powered Extensions for WinForms