UnifiedChat.Maui (1.1.4)
Installation
dotnet nuget add source --name logikonline --username your_username --password your_token dotnet add package --source logikonline --version 1.1.4 UnifiedChat.MauiAbout this package
A comprehensive chat control library for .NET MAUI applications with advanced features including:
- Multi-conversation chat interface
- AI-powered chat using UnifiedRag.Maui
- Support for multiple LLM providers (OpenAI, Claude, Together.AI, local models)
- Markdown rendering with syntax highlighting
- Full data integration with UnifiedData.Maui
- Customizable UI with bindable properties
- Touch gesture support and responsive design
- Message history persistence
UnifiedChat.Maui
A comprehensive, AI-powered chat control for .NET MAUI applications.
Features
- Multi-Conversation Support: Manage multiple chat conversations simultaneously
- AI-Powered Responses: Integrates with UnifiedRag.Maui for intelligent responses
- Multiple LLM Providers: Support for OpenAI, Claude, Together.AI, and local models
- Streaming & Non-Streaming: Choose between real-time streaming or standard responses
- Markdown Rendering: Beautiful message formatting with markdown support
- Data Persistence: Save and load conversations using UnifiedData.Maui
- Customizable UI: Bindable properties for easy customization
- DevExpress Controls: Leverages DevExpress MAUI controls for professional UI
- Cross-Platform: Works on iOS, Android, and Windows
Installation
NuGet Package
dotnet add package UnifiedChat.Maui
Dependencies
UnifiedChat.Maui requires the following packages:
- Microsoft.Maui.Controls (9.0.110+)
- DevExpress.Maui.Controls (25.1.5+)
- DevExpress.Maui.CollectionView (25.1.5+)
- DevExpress.Maui.Editors (25.1.5+)
- CommunityToolkit.Maui (12.2.0+)
- CommunityToolkit.Mvvm (8.4.0+)
- Markdig (0.42.0+)
- UnifiedRag.Maui (latest)
- MarketAlly.TouchEffect.Maui (1.0.0+)
- MarketAlly.Dialogs.Maui (1.1.0+)
Quick Start
1. Configure MauiProgram.cs
using UnifiedChat.Maui.Extensions;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
// Initialize DevExpress and CommunityToolkit first
.UseDevExpress()
.UseDevExpressCollectionView()
.UseDevExpressControls()
.UseDevExpressEditors()
.UseMauiCommunityToolkit()
// Add UnifiedChat with OpenAI
.AddUnifiedChat(
openAiApiKey: "your-api-key-here",
modelName: "gpt-4o-mini",
configureChat: options =>
{
options.EnableStreaming = true;
options.DefaultSystemPrompt = "You are a helpful assistant.";
options.MaxTokens = 2048;
});
return builder.Build();
}
}
2. Add the Control to Your Page
XAML:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:chat="clr-namespace:UnifiedChat.Maui.Controls;assembly=UnifiedChat.Maui"
x:Class="MyApp.ChatPage">
<chat:UnifiedChatControl x:Name="ChatControl"
EnableStreaming="True"
SystemPrompt="You are a helpful assistant."
ShowConversationsButton="True"
ShowSaveButton="True"/>
</ContentPage>
Code-Behind:
public partial class ChatPage : ContentPage
{
public ChatPage()
{
InitializeComponent();
}
}
3. Using Dependency Injection
public partial class ChatPage : ContentPage
{
private readonly UnifiedChatControl _chatControl;
public ChatPage(UnifiedChatControl chatControl)
{
InitializeComponent();
_chatControl = chatControl;
Content = _chatControl;
}
}
Configuration Options
Provider Setup
OpenAI
builder.AddUnifiedChat(
openAiApiKey: "your-api-key",
modelName: "gpt-4o-mini");
Anthropic Claude
builder.AddUnifiedChatWithClaude(
anthropicApiKey: "your-api-key",
modelName: "claude-3-5-sonnet-20241022");
Together.AI
builder.AddUnifiedChatWithTogetherAI(
togetherApiKey: "your-api-key",
modelName: "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo");
Local Model
builder.AddUnifiedChatWithLocalModel(
modelPath: "/path/to/model.gguf",
maxTokens: 512);
Basic Chat (No AI)
builder.AddUnifiedChatBasic();
Dynamic Settings (App-Provided IProviderSettings)
// Register your settings adapter first
builder.Services.AddSingleton<IProviderSettings, MySettingsAdapter>();
// Then add chat with dynamic settings
builder.AddUnifiedChatWithDynamicSettings(
configureChat: options =>
{
options.EnableStreaming = true;
}
);
Runtime Settings (Built-in RuntimeProviderSettings)
// Initial setup with runtime-updateable settings
builder.AddUnifiedChatWithRuntimeSettings(
provider: "openai",
apiKey: "sk-...",
modelName: "gpt-4o-mini",
configureChat: options =>
{
options.EnableStreaming = true;
}
);
// Later, update settings at runtime:
var settings = serviceProvider.GetRequiredService<RuntimeProviderSettings>();
// Update just the API key
await settings.UpdateApiKeyAsync("sk-new-key");
// Or switch to a different provider entirely
await settings.SwitchProviderAsync(
provider: "anthropic",
apiKey: "sk-ant-...",
modelName: "claude-3-5-sonnet-20241022"
);
XAML Instantiation with Lazy Service Resolution
When you create the control in XAML (without DI), services are automatically resolved from the DI container when needed:
<!-- In XAML - services will be resolved lazily -->
<chat:UnifiedChatControl
EnableStreaming="True"
SystemPrompt="You are a helpful assistant." />
How it works:
- When the control is created in XAML, the default constructor is used
- Services (
IRAGService,IUnifiedDataService) are resolved lazily fromApplication.Current.Handler.MauiContext.Services - Resolution happens automatically when sending a message
- If you registered services via
AddUnifiedChatWithDynamicSettings()or other methods, they will be available
This means you can:
- Configure services in
MauiProgram.csusing anyAddUnifiedChat*method - Create the control in XAML without constructor parameters
- AI features will work automatically when the user sends a message
// In MauiProgram.cs
builder.Services.AddSingleton<IProviderSettings, MySettingsAdapter>();
builder.AddUnifiedChatWithDynamicSettings();
// In XAML - just use the control, services resolve automatically
// <chat:UnifiedChatControl EnableStreaming="True" />
Chat Options
configureChat: options =>
{
options.EnableStreaming = true;
options.DefaultSystemPrompt = "You are a helpful assistant.";
options.ShowConversationsButton = true;
options.ShowSaveButton = true;
options.MaxTokens = 2048;
options.Temperature = 0.7;
options.AutoSaveConversations = false;
options.AutoSaveIntervalMinutes = 5;
}
Bindable Properties
| Property | Type | Default | Description |
|---|---|---|---|
ViewModel |
ChatViewModel |
auto-created | The ViewModel for the control |
EnableStreaming |
bool |
true |
Enable streaming responses |
SystemPrompt |
string |
"You are a helpful assistant." | System prompt for AI |
ShowConversationsButton |
bool |
true |
Show conversations list button |
ShowSaveButton |
bool |
true |
Show save button |
ViewModel Methods
Creating Conversations
ChatControl.ViewModel.CreateNewConversation();
Sending Messages
await ChatControl.ViewModel.SendMessageAsync();
Managing Conversations
// Delete a conversation
ChatControl.ViewModel.DeleteConversation(conversation);
// Clear active conversation
ChatControl.ViewModel.ClearActiveConversation();
// Save conversation
await ChatControl.ViewModel.SaveConversationAsync();
// Load conversation
await ChatControl.LoadConversationAsync(documentId);
Cancel Streaming
ChatControl.ViewModel.CancelStreaming();
Advanced Usage
Custom Styling
The control uses DevExpress controls and respects app themes (Light/Dark mode). You can customize colors by modifying the converters or overriding the control's resources.
Conversation Persistence
Conversations are automatically managed in memory. To persist them:
// Save current conversation
await ChatControl.ViewModel.SaveConversationAsync();
// Load a saved conversation
await ChatControl.LoadConversationAsync(documentId);
Scrolling to Latest Message
ChatControl.ScrollToLatestMessage();
Accessing the ViewModel
var viewModel = ChatControl.ViewModel;
viewModel.Conversations // ObservableCollection of all conversations
viewModel.ActiveConversation // Currently active conversation
viewModel.MessageInput // Current message input text
viewModel.IsSending // Whether a message is being sent
viewModel.IsStreaming // Whether a response is streaming
Architecture
Models
- ChatMessage: Represents a single message (user or AI)
- ChatConversation: Represents a conversation with multiple messages
ViewModels
- ChatViewModel: Main ViewModel with commands and data
Controls
- UnifiedChatControl: The main XAML control
Extensions
- ServiceCollectionExtensions: DI configuration with multiple provider support
- MauiAppBuilderExtensions: MAUI app builder extensions
Troubleshooting
AI Features Not Working
Ensure you've configured a RAG service provider in your MauiProgram.cs:
.AddUnifiedChat(openAiApiKey: "your-key")
DevExpress Controls Not Displaying
Make sure you initialize DevExpress before UnifiedChat:
builder.UseMauiApp<App>()
.UseDevExpress()
.UseDevExpressCollectionView()
.UseDevExpressControls()
.UseDevExpressEditors()
.AddUnifiedChat(...)
Messages Not Appearing
Check that the ViewModel is properly bound:
var vm = ChatControl.ViewModel;
Console.WriteLine($"Active conversation: {vm.ActiveConversation?.ConversationId}");
License
MIT License - Copyright © 2025 MarketAlly
Support
For issues, questions, or contributions:
Initial release: - Multi-conversation chat interface - AI-powered responses - Markdown rendering - Message history persistence - Cross-platform support (iOS, Android)
Dependencies
| ID | Version | Target Framework |
|---|---|---|
| UnifiedRag.Maui | 1.1.2 | net9.0-android35.0 |
| CommunityToolkit.Maui | 12.3.0 | net9.0-android35.0 |
| CommunityToolkit.Mvvm | 8.4.0 | net9.0-android35.0 |
| Indiko.Maui.Controls.Markdown | 1.3.14 | net9.0-android35.0 |
| MarketAlly.Dialogs.Maui | 1.5.0 | net9.0-android35.0 |
| MarketAlly.MABottomSheet | 1.3.0 | net9.0-android35.0 |
| MarketAlly.MALayout | 3.6.4 | net9.0-android35.0 |
| MarketAlly.MAToolbar | 1.9.9 | net9.0-android35.0 |
| MarketAlly.TouchEffect.Maui | 1.0.0 | net9.0-android35.0 |
| MarketAlly.ViewEngine | 2.5.1 | net9.0-android35.0 |
| Microsoft.Extensions.Configuration.Binder | 9.0.10 | net9.0-android35.0 |
| Microsoft.Extensions.Configuration.Json | 9.0.10 | net9.0-android35.0 |
| Microsoft.Extensions.Logging.Abstractions | 9.0.10 | net9.0-android35.0 |
| Microsoft.Maui.Controls | 9.0.120 | net9.0-android35.0 |
| Microsoft.Maui.Controls.Compatibility | 9.0.120 | net9.0-android35.0 |
| Mopups | 1.3.4 | net9.0-android35.0 |
| Syncfusion.Maui.Core | 31.2.5 | net9.0-android35.0 |
| Syncfusion.Maui.ListView | 31.2.5 | net9.0-android35.0 |
| Syncfusion.Maui.TreeView | 31.2.5 | net9.0-android35.0 |
| UnifiedRag.Maui | 1.1.2 | net9.0-ios18.0 |
| CommunityToolkit.Maui | 12.3.0 | net9.0-ios18.0 |
| CommunityToolkit.Mvvm | 8.4.0 | net9.0-ios18.0 |
| Indiko.Maui.Controls.Markdown | 1.3.14 | net9.0-ios18.0 |
| MarketAlly.Dialogs.Maui | 1.5.0 | net9.0-ios18.0 |
| MarketAlly.MABottomSheet | 1.3.0 | net9.0-ios18.0 |
| MarketAlly.MALayout | 3.6.4 | net9.0-ios18.0 |
| MarketAlly.MAToolbar | 1.9.9 | net9.0-ios18.0 |
| MarketAlly.TouchEffect.Maui | 1.0.0 | net9.0-ios18.0 |
| MarketAlly.ViewEngine | 2.5.1 | net9.0-ios18.0 |
| Microsoft.Extensions.Configuration.Binder | 9.0.10 | net9.0-ios18.0 |
| Microsoft.Extensions.Configuration.Json | 9.0.10 | net9.0-ios18.0 |
| Microsoft.Extensions.Logging.Abstractions | 9.0.10 | net9.0-ios18.0 |
| Microsoft.Maui.Controls | 9.0.120 | net9.0-ios18.0 |
| Microsoft.Maui.Controls.Compatibility | 9.0.120 | net9.0-ios18.0 |
| Mopups | 1.3.4 | net9.0-ios18.0 |
| Syncfusion.Maui.Core | 31.2.5 | net9.0-ios18.0 |
| Syncfusion.Maui.ListView | 31.2.5 | net9.0-ios18.0 |
| Syncfusion.Maui.TreeView | 31.2.5 | net9.0-ios18.0 |
| UnifiedRag.Maui | 1.1.2 | net9.0-windows10.0.19041 |
| CommunityToolkit.Maui | 12.3.0 | net9.0-windows10.0.19041 |
| CommunityToolkit.Mvvm | 8.4.0 | net9.0-windows10.0.19041 |
| Indiko.Maui.Controls.Markdown | 1.3.14 | net9.0-windows10.0.19041 |
| MarketAlly.Dialogs.Maui | 1.5.0 | net9.0-windows10.0.19041 |
| MarketAlly.MABottomSheet | 1.3.0 | net9.0-windows10.0.19041 |
| MarketAlly.MALayout | 3.6.4 | net9.0-windows10.0.19041 |
| MarketAlly.MAToolbar | 1.9.9 | net9.0-windows10.0.19041 |
| MarketAlly.TouchEffect.Maui | 1.0.0 | net9.0-windows10.0.19041 |
| MarketAlly.ViewEngine | 2.5.1 | net9.0-windows10.0.19041 |
| Microsoft.Extensions.Configuration.Binder | 9.0.10 | net9.0-windows10.0.19041 |
| Microsoft.Extensions.Configuration.Json | 9.0.10 | net9.0-windows10.0.19041 |
| Microsoft.Extensions.Logging.Abstractions | 9.0.10 | net9.0-windows10.0.19041 |
| Microsoft.Maui.Controls | 9.0.120 | net9.0-windows10.0.19041 |
| Microsoft.Maui.Controls.Compatibility | 9.0.120 | net9.0-windows10.0.19041 |
| Mopups | 1.3.4 | net9.0-windows10.0.19041 |
| Syncfusion.Maui.Core | 31.2.5 | net9.0-windows10.0.19041 |
| Syncfusion.Maui.ListView | 31.2.5 | net9.0-windows10.0.19041 |
| Syncfusion.Maui.TreeView | 31.2.5 | net9.0-windows10.0.19041 |