Carbon.Avalonia.Desktop 0.2.0

dotnet add package Carbon.Avalonia.Desktop --version 0.2.0
                    
NuGet\Install-Package Carbon.Avalonia.Desktop -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Carbon.Avalonia.Desktop" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Carbon.Avalonia.Desktop" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Carbon.Avalonia.Desktop" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Carbon.Avalonia.Desktop --version 0.2.0
                    
#r "nuget: Carbon.Avalonia.Desktop, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Carbon.Avalonia.Desktop@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Carbon.Avalonia.Desktop&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Carbon.Avalonia.Desktop&version=0.2.0
                    
Install as a Cake Tool

Carbon.Avalonia.Desktop

A comprehensive, reusable Avalonia UI control library featuring modern navigation, docking, ribbon, editors, 2D canvas, calendar/schedule, and service-based components for desktop applications.

Features

  • Navigation System — Sidebar navigation with header/footer items, horizontal/vertical orientation, and async page lifecycle
  • Docking System — Tabbed docking panels with drag-and-drop, split containers, and serialisable layout model
  • Ribbon Controls — Ribbon tabs, groups, buttons, toggle buttons, and drop-down menus
  • Editor Controls — Typed editors for all .NET numeric types, text, Base64, hexadecimal, and byte arrays with built-in validation
  • 2D Canvas (Displayer2D) — Zoomable/pannable 2D drawing surface with shape primitives, images, text, and pluggable interaction handlers
  • Calendar & Schedule — Month and week views with drag-to-move, resize, mini-calendar sidebar, and event callbacks
  • Service-Based Components — ContentDialog, Overlay, InfoBar, File/Folder dialogs via injectable services
  • Settings Controls — SettingsCard and SettingsCardExpander for configuration UIs
  • Dark/Light Theme Support — Complete theming system with dynamic resource switching
  • Compiled Bindings — Performance-optimized with compiled bindings by default
  • Host Integration — Works with Microsoft.Extensions.Hosting for clean service lifetime and IHostedService support

Requirements

  • .NET 10.0 or later
  • Avalonia 11.3+
  • CommunityToolkit.Mvvm 8.4+ (for ViewModels in your application)

Controls

Control Description
NavigationView Sidebar navigation host with Items, FooterItems, SelectedItem, and Vertical/Horizontal orientation
NavigationItem A single navigation entry with Header, IconData, PageType, and PageViewModelType

Docking

Control Description
DockingHost Top-level docking container. Holds Panes or builds from a LayoutRoot model. Handles drag-and-drop between groups
DockPane A single dockable panel with Header, PaneContent, CanClose, CanMove
DockTabGroup Tabbed container for multiple DockPane instances with drag detection and close buttons
DockSplitContainer Resizable two-pane splitter with configurable Orientation and GridLength sizes

Layout model classes for serialisation: DockPaneModel, DockTabGroupModel, DockSplitModel.

Ribbon

Control Description
Ribbon Top-level ribbon with Tabs collection and SelectedTab/SelectedIndex
RibbonTab A ribbon tab page with Header and Groups collection
RibbonGroup A named group of controls within a tab
RibbonButton Clickable ribbon button with Header, IconData, Command
RibbonToggleButton Stateful toggle button with IsChecked
RibbonDropDownButton Button that opens a popup with RibbonMenuItem items
RibbonMenuItem Data item for drop-down menus with Header, IconData, Command

Editors

All editors inherit from BaseEditor and support Title, Unit, ActionContent, SelectAllTextOnFocus (default true), HasValidationError, and ValidationErrorMessage.

Numeric Editors (with Value, Minimum, Maximum, Increment, FormatString):

Control Type
IntEditor int
ShortEditor short
LongEditor long
UIntEditor uint
UShortEditor ushort
ULongEditor ulong
SingleEditor float
DoubleEditor double
DecimalEditor decimal

Text Editors:

Control Description
TextEditor Single-line text input
MultiLineTextEditor Multi-line text input

Specialized Editors:

Control Description
Base64Editor Base64 encoded data editing
HexadecimalEditor Hexadecimal value editing
ByteArrayEditor Byte array editing

Displayer2D (2D Canvas)

Control / Class Description
Displayer2D Zoomable/pannable 2D canvas with DrawingObjects, ZoomFactor, PanX, PanY
DrawingObject Abstract base for all drawable objects (position, size, rotation, z-index, visibility)
RectangleShape Rectangle primitive
CircleShape Circle primitive
EllipseShape Ellipse primitive
LineShape Line between two points
PathShape Arbitrary path geometry
TextShape Rendered text
ImageShape Bitmap image
DrawingObjectGroup Groups objects with shared visibility/transform
LineMovingObjectGroup Composite group: movable line with two independently-draggable endpoint handles
RectangleRoiGroup Composite group: resizable rectangle ROI with corner/edge drag handles
UserInteraction Base class for pluggable input handlers (pan, zoom, selection)
DragInteraction Built-in pan/zoom interaction

Calendar & Schedule

Control Description
CalendarSchedule Full calendar with month/week views, drag-to-move, edge-resize, mini-calendar sidebar
CalendarScheduleItem Data class: Title, Start, End, Color, Description

Events: ItemMoved, ItemResized with CalendarScheduleItemChangedEventArgs.

Dialogs & Overlays

Control Description
ContentDialog Modal dialog overlay with primary/secondary/close buttons and ShowAsync()
InfoBar In-app notification bar with Severity (Info/Success/Warning/Error)
Overlay Full-screen overlay host for arbitrary content

Settings

Control Description
SettingsCard Static settings row with Header, Description, IconData, and content slot
SettingsCardExpander Expandable settings card with IsExpanded toggle

Services

Interface Implementation Description
INavigationService NavigationService Manages navigation items, selection, and async page lifecycle (OnAppearingAsync/OnDisappearingAsync)
IContentDialogService ContentDialogService Shows modal dialogs via a registered ContentDialog host
IInfoBarService InfoBarService Shows notification bars via a registered InfoBar host
IOverlayService OverlayService Shows full-screen overlays via a registered Overlay host
IFileDialogService FileDialogService Wraps IStorageProvider for open/save file dialogs (with extension methods for simplified usage)
IFolderDialogService FolderDialogService Wraps IStorageProvider for folder picker dialogs (with extension methods for simplified usage)

Page ViewModels can implement INavigationViewModel for lifecycle hooks:

  • OnDisappearingAsync() — called before navigating away; return false to cancel
  • OnAppearingAsync() — called after the page becomes active

Installation

1. Add Package Reference

dotnet add package CarbonAvaloniaDesktop

2. Include Theme Resources

In your App.axaml, include the Carbon theme resources:

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="YourApp.App">
  <Application.Styles>
    <FluentTheme />
    <StyleInclude Source="avares://Carbon.Avalonia.Desktop/Themes/Fluent.axaml" />
  </Application.Styles>
</Application>

3. Set Up Hosting and Services

Carbon uses Microsoft.Extensions.Hosting for clean service lifetime management. Configure the host in Program.cs:

using Avalonia;
using Microsoft.Extensions.Hosting;

namespace YourApp;

sealed class Program
{
    internal static IHost? AppHost { get; private set; }

    [STAThread]
    public static void Main(string[] args)
    {
        AppHost = Host.CreateDefaultBuilder(args)
            .ConfigureServices((_, services) =>
            {
                services.AddHostedServices();   // your IHostedService registrations
                services.AddCarbonServices();   // Carbon service singletons
                services.AddPagesAndViewModels(); // views (Transient) + view models (Singleton)
            })
            .Build();

        AppHost.Start();

        BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);

        // Clean shutdown after the window closes
        AppHost.StopAsync().GetAwaiter().GetResult();
        AppHost.Dispose();
    }

    public static AppBuilder BuildAvaloniaApp()
        => AppBuilder.Configure<App>()
            .UsePlatformDetect()
            .WithInterFont()
            .LogToTrace();
}

Organise your registrations with extension methods:

using Carbon.Avalonia.Desktop.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace YourApp;

public static class ServiceCollectionExtensions
{
    extension(IServiceCollection services)
    {
        public void AddHostedServices()
        {
            // Register your IHostedService implementations here
            _ = services.AddHostedService<ApiHostedService>();
        }

        public void AddCarbonServices()
        {
            _ = services.AddSingleton<INavigationService, NavigationService>();
            _ = services.AddSingleton<IContentDialogService, ContentDialogService>();
            _ = services.AddSingleton<IInfoBarService, InfoBarService>();
            _ = services.AddSingleton<IOverlayService, OverlayService>();
            _ = services.AddSingleton<IFileDialogService, FileDialogService>();
            _ = services.AddSingleton<IFolderDialogService, FolderDialogService>();
        }

        public void AddPagesAndViewModels()
        {
            _ = services.AddSingleton<MainWindow>();
            _ = services.AddSingleton<MainWindowViewModel>();

            // Views are Transient so each navigation creates a fresh instance
            _ = services.AddTransient<HomePageView>();
            _ = services.AddTransient<SettingsPageView>();

            // ViewModels are Singleton to preserve state across navigations
            _ = services.AddSingleton<HomePageViewModel>();
            _ = services.AddSingleton<SettingsPageViewModel>();
        }
    }
}

4. Configure App.axaml.cs

Resolve services from the host and register Carbon host controls:

using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Carbon.Avalonia.Desktop.Services;
using Microsoft.Extensions.DependencyInjection;

namespace YourApp;

public partial class App : Application
{
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {
        var services = Program.AppHost?.Services ?? BuildDesignerServices();

        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            var mainWindow = services.GetRequiredService<MainWindow>();
            var vm = services.GetRequiredService<MainWindowViewModel>();
            mainWindow.DataContext = vm;

            // Register service hosts
            services.GetRequiredService<IContentDialogService>().RegisterHost(mainWindow.HostDialog);
            services.GetRequiredService<IOverlayService>().RegisterHost(mainWindow.HostOverlay);
            services.GetRequiredService<IInfoBarService>().RegisterHost(mainWindow.HostInfoBar);
            services.GetRequiredService<IFileDialogService>().SetStorageProvider(mainWindow.StorageProvider);
            services.GetRequiredService<IFolderDialogService>().SetStorageProvider(mainWindow.StorageProvider);

            desktop.MainWindow = mainWindow;
        }

        base.OnFrameworkInitializationCompleted();
    }

    /// <summary>
    /// Fallback for the Avalonia Designer, which bypasses Program.Main().
    /// </summary>
    private static IServiceProvider BuildDesignerServices()
    {
        var collection = new ServiceCollection();
        collection.AddCarbonServices();
        collection.AddPagesAndViewModels();
        return collection.BuildServiceProvider();
    }
}

5. Set Up Host Controls in MainWindow

For ContentDialog, Overlay, and InfoBar services, add host controls as siblings in your MainWindow.axaml:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="using:Carbon.Avalonia.Desktop.Controls"
        x:Class="YourApp.MainWindow">

  <Panel>
    
    <ContentControl Content="{Binding CurrentPage}" />

    
    <controls:ContentDialog x:Name="HostDialog" />
    <controls:Overlay x:Name="HostOverlay" />
    <controls:InfoBar x:Name="HostInfoBar" />
  </Panel>
</Window>

Adding an IHostedService

The hosting setup makes it easy to run background services alongside your Avalonia app. Here is the ApiHostedService from the tester application, which spins up a Minimal API web server:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace YourApp;

public class ApiHostedService(IConfiguration configuration) : IHostedService
{
    private WebApplication? _app;

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        var port = configuration.GetValue("Api:Port", 5100);
        var title = configuration.GetValue("Api:Title", "My App API");

        var builder = WebApplication.CreateSlimBuilder();
        builder.WebHost.UseUrls($"http://localhost:{port}");

        _app = builder.Build();

        _app.MapGet("/", () => Results.Ok(new { Title = title, Status = "Running" }));
        _app.MapGet("/api/info", () => Results.Ok(new
        {
            Title = title,
            Port = port,
            Environment.MachineName,
            StartedAt = DateTime.UtcNow
        }));

        await _app.StartAsync(cancellationToken);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        if (_app is not null)
        {
            await _app.StopAsync(cancellationToken);
            await _app.DisposeAsync();
        }
    }
}

Register it in your AddHostedServices() method:

public void AddHostedServices()
{
    _ = services.AddHostedService<ApiHostedService>();
}

Configure port and title via appsettings.json:

{
  "Api": {
    "Port": 5100,
    "Title": "My App API"
  }
}

The host starts before the Avalonia window opens and shuts down cleanly after it closes, so hosted services run for the entire application lifetime.

Usage Examples

public class MainWindowViewModel : ViewModelBase
{
    private readonly INavigationService _navigationService;

    public MainWindowViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;

        _navigationService.Items.Add(new NavigationItem
        {
            Header = "Home",
            IconData = IconService.CreateGeometry(Icon.House, IconType.regular),
            PageType = typeof(HomePageView),
            PageViewModelType = typeof(HomePageViewModel)
        });
    }
}

ContentDialog Service

var result = await _dialogService.ShowMessageAsync(
    title: "Confirm Action",
    content: "Are you sure you want to proceed?",
    primaryButtonText: "Yes",
    closeButtonText: "No"
);

if (result == DialogResult.Primary)
{
    // User clicked Yes
}

InfoBar Service

await _infoBarService.ShowAsync(bar =>
{
    bar.Title = "Success";
    bar.Message = "Operation completed successfully.";
    bar.Severity = InfoBarSeverity.Success;
});

Overlay Service

await _overlayService.ShowAsync(new LoadingView());

// Later...
await _overlayService.HideAsync();

File Dialog Service

var files = await _fileDialogService.ShowOpenFileDialogAsync(
    title: "Open File",
    allowMultiple: false,
    filter: new[] { new FilePickerFileType("Text Files") { Patterns = new[] { "*.txt" } } }
);

Folder Dialog Service

var folders = await _folderDialogService.ShowOpenFolderDialogAsync(
    title: "Select Folder",
    allowMultiple: false
);

Editor Controls

<editors:IntEditor Title="Port"
                   Unit="TCP"
                   Value="{Binding Port}"
                   Minimum="1"
                   Maximum="65535"
                   HasValidationError="{Binding HasPortError}"
                   ValidationErrorMessage="{Binding PortErrorMessage}" />

Project Structure

Carbon.Avalonia.Desktop/
├── Controls/
│   ├── Navigation/          # NavigationView, NavigationItem
│   ├── Docking/             # DockingHost, DockPane, DockTabGroup, DockSplitContainer
│   ├── Ribbon/              # Ribbon, RibbonTab, RibbonGroup, RibbonButton, etc.
│   ├── Editors/             # BaseEditor, typed editors (Int, Double, Text, Base64, etc.)
│   ├── CalendarSchedule/    # CalendarSchedule, CalendarScheduleItem, CalendarViewMode, ScheduleInteractionMode, ScheduleDragSession, CalendarScheduleItemChangedEventArgs
│   ├── ContentDialog/       # ContentDialog, DefaultButton, DialogResult
│   ├── InfoBar/             # InfoBar, InfoBarSeverity
│   ├── Displayer2D/
│   │   ├── Groups/          # LineMovingObjectGroup, RectangleRoiGroup
│   │   └── Shapes/          # Shape primitives + MovedEventArgs
│   ├── Overlay.cs           # Overlay host control
│   ├── SettingsCard.cs      # Static settings row
│   └── SettingsCardExpander.cs  # Expandable settings card
├── Services/
│   ├── NavigationService.cs
│   ├── ContentDialogService.cs
│   ├── InfoBarService.cs
│   ├── OverlayService.cs
│   ├── FileDialogService.cs
│   └── FolderDialogService.cs
└── Themes/
    ├── Fluent.axaml          # Main theme include
    ├── Colors.axaml          # Color definitions (Dark/Light variants)
    └── Brushes.axaml         # Brush resources

Key Patterns

  • TemplatedControls — All custom controls use TemplatedControl, not UserControl
  • ViewLocator — Automatic view resolution by replacing "ViewModel" with "View" in type names
  • Service Host Pattern — Dialog/overlay/infobar services require host controls registered at startup
  • Two-Way Bindings — Use {Binding ..., RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay} in templates ({TemplateBinding} is one-way only)
  • Theme Resources — Use {DynamicResource} for theme-reactive styling
  • HostingMicrosoft.Extensions.Hosting manages the app lifecycle; IHostedService implementations run alongside the Avalonia window

Theme System

Access theme colors and brushes using dynamic resources:

<Border Background="{DynamicResource CarbonSurfacePrimaryBrush}"
        BorderBrush="{DynamicResource CarbonBorderPrimaryBrush}" />

Available resource prefixes:

  • CarbonBackground* — Background colors
  • CarbonSurface* — Surface/card backgrounds
  • CarbonBorder* — Border colors
  • CarbonForeground* — Text colors
  • CarbonAccent* — Accent colors
  • CarbonSuccess*, CarbonWarning*, CarbonError* — Semantic colors

Development

Build

dotnet build

Run Tester Application

dotnet run --project CarbonAvaloniaDesktopTester

The tester application (CarbonAvaloniaDesktopTester) provides live examples and a testing playground for all controls.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.2.0 97 4/29/2026
0.1.0 140 3/9/2026