![]() |
VOOZH | about |
dotnet add package CheapAvaloniaBlazor --version 3.2.0
NuGet\Install-Package CheapAvaloniaBlazor -Version 3.2.0
<PackageReference Include="CheapAvaloniaBlazor" Version="3.2.0" />
<PackageVersion Include="CheapAvaloniaBlazor" Version="3.2.0" />Directory.Packages.props
<PackageReference Include="CheapAvaloniaBlazor" />Project file
paket add CheapAvaloniaBlazor --version 3.2.0
#r "nuget: CheapAvaloniaBlazor, 3.2.0"
#:package CheapAvaloniaBlazor@3.2.0
#addin nuget:?package=CheapAvaloniaBlazor&version=3.2.0Install as a Cake Addin
#tool nuget:?package=CheapAvaloniaBlazor&version=3.2.0Install as a Cake Tool
Build cross-platform desktop applications using Blazor Server, Avalonia, and Photino.
Combines Blazor Server + MudBlazor + Avalonia + Photino to create native desktop apps with full file system access across Windows, Linux, and macOS using familiar Razor pages and C# components.
PRE-ALPHA HOBBY PROJECT This is an experimental project developed as a personal hobby. Expect breaking changes, incomplete features, and limited support. Use at your own risk in non-production environments.
Building cross-platform desktop apps traditionally requires learning different UI frameworks for each platform or dealing with complex native interop. CheapAvaloniaBlazor allows you to use existing web development skills (HTML, CSS, Blazor, C#) to build desktop applications with native capabilities.
Complete documentation available in the folder:
# Install templates
dotnet new install CheapAvaloniaBlazor.Templates
# Create a minimal app (MudBlazor + basic window)
dotnet new cheapblazor -n MyDesktopApp
# Or create a full-featured app (all desktop services enabled)
dotnet new cheapblazor-full -n MyDesktopApp
cd MyDesktopApp
dotnet run
| Template | Short Name | Description |
|---|---|---|
| CheapAvaloniaBlazor Desktop App | cheapblazor |
Clean starting point — MudBlazor + basic window |
| CheapAvaloniaBlazor Desktop App (Full Featured) | cheapblazor-full |
All features: tray, notifications, settings, hotkeys, menu bar, multi-window, drag-drop |
# Create a new console project
dotnet new console -n MyDesktopApp
cd MyDesktopApp
# Add CheapAvaloniaBlazor package
dotnet add package CheapAvaloniaBlazor
More installation options: See the for Visual Studio GUI instructions, Avalonia templates, and troubleshooting.
1. Update your .csproj to use Razor SDK:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="CheapAvaloniaBlazor" Version="3.1.2" />
</ItemGroup>
</Project>
2. Replace Program.cs:
using CheapAvaloniaBlazor.Extensions;
using CheapAvaloniaBlazor.Hosting;
namespace MyDesktopApp;
class Program
{
[STAThread]
public static void Main(string[] args)
{
new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.AddMudBlazor()
.RunApp(args);
}
}
3. Add Blazor components (App.razor as HTML root, Routes.razor for routing, MainLayout.razor, Index.razor, etc.)
Full tutorial: See the for complete step-by-step instructions with all files.
blazor.web.js Is ServedIn .NET 10, blazor.web.js ships in the Microsoft.AspNetCore.App.Internal.Assets NuGet package. Its MSBuild targets register it as a static web asset — but only for OutputType=Exe projects using Microsoft.NET.Sdk.Web. Desktop apps use OutputType=WinExe, so the framework skips them entirely regardless of SDK choice.
CheapAvaloniaBlazor handles this automatically via BlazorFrameworkExtractor:
wwwroot/_framework/blazor.web.js already exists~/.nuget/packages/microsoft.aspnetcore.app.internal.assets/{version}/_framework/){contentRoot}/wwwroot/_framework/blazor.web.jsUseStaticFiles() middleware then serves it at /_framework/blazor.web.jsNo consumer action required — this is transparent to the application.
Full system tray integration with icon management, context menus, and minimize/close-to-tray behavior.
new HostBuilder()
.WithTitle("My App")
.EnableSystemTray()
.CloseToTray()
.WithTrayTooltip("My App - Click to restore")
.AddMudBlazor()
.RunApp(args);
Control the tray from Blazor components:
@inject ISystemTrayService SystemTray
// Minimize to tray (hides window, shows tray icon)
SystemTray.MinimizeToTray();
// Custom context menu items
SystemTray.AddTrayMenuItem(
TrayMenuItemDefinition.Create("Settings", () => NavigateToSettings()));
// Checkable menu items, submenus, separators, async handlers
SystemTray.SetTrayMenu([
TrayMenuItemDefinition.CreateCheckable("Dark Mode", isChecked: true, onToggle: ToggleTheme),
TrayMenuItemDefinition.Separator(),
TrayMenuItemDefinition.CreateAsync("Sync", async () => await SyncDataAsync())
]);
Note: When
EnableDevToolsis true, the taskbar icon will remain visible after minimizing to tray. This is a Photino/WebView2 limitation - the DevTools window maintains taskbar presence. DisableEnableDevToolsfor clean tray-only behavior.
Two independent notification channels for different use cases:
Desktop Toasts - Avalonia-rendered overlay notifications. Cross-platform, always works, styled by type:
@inject INotificationService Notifications
// Show a desktop toast (Information, Success, Warning, Error)
Notifications.ShowDesktopNotification("Build Complete", "All tests passed",
NotificationType.Success);
// Custom expiration
Notifications.ShowDesktopNotification("Warning", "Disk space low",
NotificationType.Warning, TimeSpan.FromSeconds(10));
System Notifications - OS notification center via JavaScript Web Notification API (opt-in):
@inject INotificationService Notifications
@inject IJSRuntime JSRuntime
// Requires .EnableSystemNotifications() in HostBuilder
await Notifications.ShowSystemNotificationAsync(JSRuntime, "Alert", "New message received");
Configure notification behavior:
new HostBuilder()
.EnableSystemNotifications() // Opt-in to OS notifications
.WithNotificationPosition(NotificationPosition.TopRight) // Toast position
.WithMaxNotifications(5) // Max visible toasts
.AddMudBlazor()
.RunApp(args);
JSON-based settings service with key-value and typed section APIs. Thread-safe, lazy-loaded, auto-save.
new HostBuilder()
.WithTitle("My App")
.WithSettingsAppName("MyApp") // Folder under %LocalAppData%
.AutoSaveSettings() // Auto-save on every change (default: true)
.AddMudBlazor()
.RunApp(args);
Key-value API - Store and retrieve individual values:
@inject ISettingsService Settings
// Set a value (auto-saves)
await Settings.SetAsync("theme", "dark");
await Settings.SetAsync("fontSize", 14);
// Get a value with default fallback
var theme = await Settings.GetAsync<string>("theme", "light");
// Check existence and delete
if (await Settings.ExistsAsync("oldKey"))
await Settings.DeleteAsync("oldKey");
Typed section API - Work with strongly-typed settings classes:
// Define your settings class
public class AppSettings
{
public bool IsDarkMode { get; set; } = true;
public List<string> RecentFiles { get; set; } = [];
}
// Read a section (key = class name)
var appSettings = await Settings.GetSectionAsync<AppSettings>();
// Update a section (read-modify-write, auto-saves)
await Settings.UpdateSectionAsync<AppSettings>(s => s.IsDarkMode = false);
// Replace a section entirely
await Settings.SetSectionAsync(new AppSettings { IsDarkMode = true });
Settings are stored at %LocalAppData%/{appName}/settings.json. Configure the location with WithSettingsFolder() or WithSettingsFileName().
Subscribe to native window lifecycle events from Blazor components. Track window state and react to minimize, maximize, restore, and focus changes.
@inject IAppLifecycleService Lifecycle
// Read-only state properties
var minimized = Lifecycle.IsMinimized;
var maximized = Lifecycle.IsMaximized;
var focused = Lifecycle.IsFocused;
// Subscribe to events
Lifecycle.Minimized += () => Console.WriteLine("Window minimized");
Lifecycle.Maximized += () => Console.WriteLine("Window maximized");
Lifecycle.Restored += () => Console.WriteLine("Window restored");
Lifecycle.Activated += () => Console.WriteLine("Window focused");
Lifecycle.Deactivated += () => Console.WriteLine("Window lost focus");
// Prevent close with cancellation support
Lifecycle.Closing += (sender, args) =>
{
if (HasUnsavedChanges)
args.Cancel = true; // Prevent window from closing
};
No builder configuration required - IAppLifecycleService is always available.
Detect OS dark/light mode preference and automatically react to runtime theme switches.
@inject IThemeService Theme
// Read current OS theme
var theme = Theme.CurrentTheme; // SystemTheme.Light or SystemTheme.Dark
var isDark = Theme.IsDarkMode; // Convenience bool
// React to OS theme changes at runtime
Theme.ThemeChanged += (newTheme) =>
{
// Auto-sync MudBlazor dark mode with OS preference
_isDarkMode = newTheme == SystemTheme.Dark;
InvokeAsync(StateHasChanged);
};
Uses Avalonia's built-in platform theme detection under the hood. No builder configuration required - IThemeService is always available.
Register system-wide keyboard shortcuts that fire even when the application window is not focused. Supported on Windows and Linux, with IsSupported for runtime platform detection.
Platform support:
RegisterHotKey APIXGrabKey fallback (X11 sessions and XWayland)IsSupported returns false)@inject IHotkeyService Hotkeys
// Check platform support
if (Hotkeys.IsSupported)
{
// Register a global hotkey (Ctrl+Shift+H)
var id = Hotkeys.RegisterHotkey(
HotkeyModifiers.Ctrl | HotkeyModifiers.Shift,
Key.H,
() => Console.WriteLine("Hotkey pressed!"));
// Unregister when no longer needed
Hotkeys.UnregisterHotkey(id);
// Or unregister all at once
Hotkeys.UnregisterAll();
}
// Global event for any hotkey press
Hotkeys.HotkeyPressed += (hotkeyId) =>
Console.WriteLine($"Hotkey {hotkeyId} fired");
Supported keys (via Avalonia.Input.Key):
A–ZD0–D9F1–F24NumPad0–NumPad9Home, End, PageUp, PageDown, Insert, DeleteLeft, Up, Right, DownSpace, Return, Escape, Tab, BackPrintScreen, Pause, CapsLock, NumLock, ScrollModifiers (combinable with |): Ctrl, Alt, Shift, Win
No builder configuration required - IHotkeyService is always available. Automatically selects the best backend for the current platform.
Attach a Win32 native menu bar to the Photino window with File, Edit, View, Help menus or any custom layout. Supports mnemonics (Alt+F), accelerator display text, checkable items, and dynamic enable/disable.
using CheapAvaloniaBlazor.Models;
new HostBuilder()
.WithTitle("My App")
.WithMenuBar(
[
MenuItemDefinition.CreateSubMenu("&File",
[
MenuItemDefinition.Create("&New", () => NewFile(), id: "file_new", accelerator: "Ctrl+N"),
MenuItemDefinition.Create("&Open...", () => OpenFile(), id: "file_open", accelerator: "Ctrl+O"),
MenuItemDefinition.Separator(),
MenuItemDefinition.Create("E&xit", () => Environment.Exit(0), id: "file_exit"),
]),
MenuItemDefinition.CreateSubMenu("&View",
[
MenuItemDefinition.CreateCheckable("&Dark Mode", false, () => ToggleTheme(), id: "view_dark"),
]),
MenuItemDefinition.CreateSubMenu("&Help",
[
MenuItemDefinition.Create("&About", () => ShowAbout(), id: "help_about"),
]),
])
.AddMudBlazor()
.RunApp(args);
Control from Blazor components:
@inject IMenuBarService MenuBar
// Enable/disable menu items dynamically
MenuBar.EnableMenuItem("file_new", isEnabled: false);
// Toggle check state
MenuBar.CheckMenuItem("view_dark", isChecked: true);
// React to any menu click
MenuBar.MenuItemClicked += (menuItemId) =>
Console.WriteLine($"Menu clicked: {menuItemId}");
Platform support: Windows only (Win32 native menu). IsSupported returns false on Linux/macOS. Accelerator text is display-only — use IHotkeyService for actual keyboard bindings.
Create child windows and modal dialogs from Blazor components. Each window runs on its own background thread with an independent Blazor SignalR circuit, connected to the same embedded server.
Open a child window (URL path):
@inject IWindowService WindowService
var windowId = await WindowService.CreateWindowAsync(
WindowOptions.FromUrl("/settings", "Settings"));
Open a modal dialog (component type, no @page needed):
var options = WindowOptions.FromComponent<SettingsDialog>("Settings");
options.Width = 500;
options.Height = 400;
options.Resizable = false;
ModalResult result = await WindowService.CreateModalAsync(options);
if (result.Confirmed)
{
var data = result.GetData<Dictionary<string, object>>();
// Use the returned data
}
Complete a modal from inside the dialog component:
[Parameter] public string? WindowId { get; set; }
// Save button
WindowService.CompleteModal(WindowId, ModalResult.Ok(myData));
// Cancel button
WindowService.CompleteModal(WindowId, ModalResult.Cancel());
Inter-window messaging:
// Send to a specific window
WindowService.SendMessage(targetWindowId, "refresh", payload);
// Broadcast to all windows
WindowService.BroadcastMessage("theme_changed", newTheme);
// Receive messages (filter by your own window ID)
WindowService.MessageReceived += (targetId, type, payload) =>
{
if (targetId == myWindowId || targetId == "*")
HandleMessage(type, payload);
};
Platform support: Child windows work on all platforms. Modal behavior (parent window disabling) is Windows-only via Win32 EnableWindow. On Linux/macOS, IsModalSupported returns false but dialogs still open as regular windows.
Limits: When using WindowOptions.ComponentType, each distinct component type is registered in an internal security whitelist (prevents arbitrary type instantiation from URL parameters). The whitelist is capped at 256 distinct types (Constants.Window.MaxRegisteredComponentTypes). Re-using the same type across multiple windows does not count again. This limit is a safety guard — typical apps use far fewer component types. URL-path windows (WindowOptions.FromUrl) are not affected.
Receive file drop events from the OS in Blazor components. Uses HTML5 drag-and-drop in WebView2, bridged to C# via the Photino message channel.
@inject IDragDropService DragDropService
// Subscribe to file drops
DragDropService.FilesDropped += (files) =>
{
foreach (var file in files)
{
Console.WriteLine($"{file.Name} ({file.Size} bytes, {file.ContentType})");
}
};
// Visual feedback during drag-over
DragDropService.DragEnter += () => showDropZone = true;
DragDropService.DragLeave += () => showDropZone = false;
// Check drag state at any time
if (DragDropService.IsDragOver) { /* highlight UI */ }
File metadata: Name, Size, ContentType, LastModified. File system paths (FilePath) are null in V1 — WebView2's browser sandbox does not expose paths from HTML5 drag events. Native file path extraction (Win32 IDropTarget) is planned for V2.
Cross-platform: Works on Windows, Linux, and macOS. Auto-initialized when the application starts — no builder configuration needed.
Enabled by default - Shows a loading screen while your app initializes.
// Customize splash screen
new HostBuilder()
.WithTitle("My App")
.WithSplashScreen("My App", "Loading workspace...")
.AddMudBlazor()
.RunApp(args);
Full documentation: See for customization options, custom content, and advanced configuration.
Full native desktop capabilities with ValueTask optimization for zero-allocation performance:
@inject IDesktopInteropService Desktop
// File dialogs
var file = await Desktop.OpenFileDialogAsync(new FileDialogOptions
{
Title = "Select a file",
Filters = [new FileFilter { Name = "Images", Extensions = ["png", "jpg"] }]
});
var savePath = await Desktop.SaveFileDialogAsync();
var folder = await Desktop.OpenFolderDialogAsync();
// Window management
await Desktop.MinimizeWindowAsync();
await Desktop.MaximizeWindowAsync();
await Desktop.SetWindowTitleAsync("New Title");
var state = await Desktop.GetWindowStateAsync();
// Clipboard
await Desktop.SetClipboardTextAsync("Copied!");
var text = await Desktop.GetClipboardTextAsync();
// System integration
await Desktop.OpenUrlInBrowserAsync("https://github.com");
var appData = await Desktop.GetAppDataPathAsync();
Full API reference: See for all available methods and examples.
Comprehensive diagnostic system for troubleshooting:
new HostBuilder()
.EnableDiagnostics() // Detailed startup and operation logging
.AddMudBlazor()
.RunApp(args);
Full guide: See for DiagnosticLogger usage and troubleshooting scenarios.
Configure your application with an intuitive fluent interface:
new HostBuilder()
// Window
.WithTitle("My App").WithSize(1400, 900).WithIcon("icon.ico")
.Chromeless(false).CenterWindow()
// Splash Screen
.WithSplashScreen("My App", "Loading...")
// System Tray
.EnableSystemTray().CloseToTray()
.WithTrayTooltip("My App").WithTrayIcon("tray.ico")
// Notifications
.EnableSystemNotifications()
.WithNotificationPosition(NotificationPosition.BottomRight)
.WithMaxNotifications(3)
// Settings Persistence
.WithSettingsAppName("MyApp")
.AutoSaveSettings()
// Menu Bar (Windows only)
.WithMenuBar([...])
// Server
.UsePort(5001).UseHttps(true)
// Diagnostics
.EnableDiagnostics().EnableDevTools(true)
// UI Framework
.AddMudBlazor()
// Advanced options
.ConfigureOptions(opts => { /* ... */ })
.RunApp(args);
Complete reference: See for all HostBuilder methods, SignalR configuration, custom pipeline/endpoints, and more.
MyDesktopApp/
├── Program.cs # Application entry point
├── Components/
│ ├── App.razor # HTML document root (loads scripts, CSS, renders Routes)
│ ├── Routes.razor # Blazor router configuration
│ └── MainLayout.razor # Main application layout
├── Pages/
│ ├── Index.razor # Home page
│ └── Files.razor # File management page
├── wwwroot/ # Static web assets
│ └── css/
└── Services/ # Your business logic
└── IMyService.cs
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Avalonia │ │ Blazor Server │ │ Photino │
│ (Desktop │◄──►│ (Web UI & │◄──►│ (WebView │
│ Framework) │ │ Components) │ │ Hosting) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
▲ ▲ ▲
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Native OS │ │ MudBlazor │ │ File System │
│ Integration │ │ (Material UI) │ │ Access │
└─────────────────┘ └──────────────────┘ └─────────────────┘
| Component | Technology | Version |
|---|---|---|
| UI Layer | Blazor Server + MudBlazor | 8.15.0 |
| Desktop Framework | Avalonia | 11.3.11 |
| WebView Host | Photino.NET | 4.0.16 |
| Backend | ASP.NET Core | .NET 10.0 |
| Interop | Custom desktop services | Built-in |
| Feature | Windows | Linux | macOS |
|---|---|---|---|
| Blazor UI / MudBlazor | Tested | Untested | Untested |
| File Dialogs | Tested | Untested | Untested |
| Window Management | Tested | Untested | Untested |
| Clipboard | Tested | Untested | Untested |
| Desktop Toasts | Tested | Untested | Untested |
| System Tray | Tested | Varies by DE | Untested |
| Minimize to Tray (hide window) | Tested | Fallback to minimize | Fallback to minimize |
| System Notifications (JS) | Tested | Untested | Untested |
| Settings Persistence | Tested | Untested | Untested |
| App Lifecycle Events | Tested | Untested | Untested |
| Theme Detection | Tested | Untested | Untested |
| Global Hotkeys | Tested | Tested (D-Bus/X11) | Not supported |
| Native Menu Bar | Tested | Not supported | Not supported |
| Multi-Window / Child Windows | Tested | Untested | Untested |
| Modal Dialogs (parent disable) | Tested | Not supported | Not supported |
Minimize to Tray uses Windows
user32.dllP/Invoke to fully hide the window. On Linux/macOS, the window falls back to a regular minimize (taskbar icon stays visible). System Tray behavior on Linux depends on the desktop environment's support for Avalonia'sTrayIconAPI.
| Service | Lifetime | Purpose |
|---|---|---|
IDesktopInteropService |
Scoped | File dialogs, window control, clipboard, system paths |
INotificationService |
Singleton | Desktop toasts + OS system notifications |
ISystemTrayService |
Singleton | Tray icon, context menu, minimize/restore to tray |
ISettingsService |
Singleton | JSON settings persistence (key-value + typed sections) |
IAppLifecycleService |
Singleton | Window lifecycle events (minimize, maximize, focus, close) |
IThemeService |
Singleton | OS dark/light mode detection and runtime change tracking |
IHotkeyService |
Singleton | System-wide global hotkeys (Windows + Linux, IsSupported for detection) |
IMenuBarService |
Singleton | Native Win32 menu bar (Windows only, IsSupported for detection) |
IWindowService |
Singleton | Child windows, modal dialogs, inter-window messaging |
IDiagnosticLoggerFactory |
Singleton | Conditional diagnostic logging |
PhotinoMessageHandler |
Singleton | JavaScript ↔ C# bridge communication |
Location: samples/MinimalApp/ - Absolute minimum code to run a Blazor desktop app.
Location: samples/DesktopFeatures/ - Demonstrates all desktop interop features:
A video editing workflow tool built with CheapAvaloniaBlazor that demonstrates the framework's capabilities for building desktop applications with complex features.
Repository: https://github.com/CheapNud/CheapShotcutRandomizer
# Command Line / VS Code Users
dotnet run
# Visual Studio Users
Press F5 or Debug > Start Debugging
# Hot reload enabled automatically in both environments
# Make changes to .razor files and see instant updates
# Build release version
dotnet publish -c Release -r win-x64 --self-contained
# Create single-file executable
dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
# Cross-platform builds
dotnet publish -c Release -r linux-x64 --self-contained -p:PublishSingleFile=true
dotnet publish -c Release -r osx-x64 --self-contained -p:PublishSingleFile=true
Avalonia 11.3.11 - Desktop frameworkMudBlazor 8.15.0 - Material Design componentsPhotino.NET 4.0.16 - WebView hostingTmds.DBus.Protocol 0.22.0 - D-Bus protocol for Linux global hotkeysMicrosoft.AspNetCore.App - ASP.NET Core framework referenceBuild Errors
# Ensure correct .NET version
dotnet --version # Should be 10.0+
# Clear and restore packages
dotnet clean
dotnet restore
dotnet build
Window Doesn't Appear
builder.UsePort(8080)MudBlazor Styles Missing
App.razor:
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
AddMudBlazor() is called in HostBuilderBlack Screen / blazor.web.js 404
dotnet restore to ensure Microsoft.AspNetCore.App.Internal.Assets is in the NuGet cacheSdk.Razor: the library extracts blazor.web.js at runtime from the NuGet cache — check startup logs for extraction messagesSdk.Web: verify MapStaticAssets() is in the pipeline (called by UseCheapBlazorDesktop())%LocalAppData%\Photino\EBWebView\Default\Cache\Platform Compatibility Issues
File Dialog Not Working
dotnet add package CheapAvaloniaBlazorIDesktopInteropService injectionTaskbar Icon Stays Visible When Minimized to Tray
EnableDevTools is true - the DevTools window keeps the taskbar icon aliveEnableDevTools for production or when testing tray behaviorvar builder = new HostBuilder()
.WithTitle("My App")
.EnableConsoleLogging() // Show console window for logging
.EnableDevTools() // Enable F12 developer tools
.EnableContextMenu() // Enable right-click menu (default: true)
.EnableDiagnostics() // Comprehensive diagnostic logging
.AddMudBlazor();
dotnet new cheapblazor and cheapblazor-full project scaffoldingThis is a hobby project - support is provided on a best-effort basis.
MIT License - Use freely in personal and commercial projects.
# Install templates
dotnet new install CheapAvaloniaBlazor.Templates
# Create and run a new app
dotnet new cheapblazor -n MyFirstDesktopApp
cd MyFirstDesktopApp
dotnet run
Questions or issues? Open an issue for feedback.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on CheapAvaloniaBlazor:
| Package | Downloads |
|---|---|
|
CheapHelpers.Avalonia.Bridge
Bridge package integrating CheapAvaloniaBlazor desktop notifications with CheapHelpers notification system. Provides DesktopNotificationChannel adapter allowing desktop OS notifications to participate in the unified notification system. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.0 | 90 | 6/11/2026 |
| 3.1.2 | 97 | 6/10/2026 |
| 3.1.1 | 142 | 5/9/2026 |
| 3.1.0 | 108 | 5/9/2026 |
| 3.0.0 | 529 | 2/27/2026 |
| 2.1.1 | 196 | 2/12/2026 |
| 2.0.2 | 162 | 1/29/2026 |
| 2.0.1 | 130 | 1/29/2026 |
| 2.0.0 | 137 | 1/28/2026 |
| 1.2.4 | 138 | 1/27/2026 |
| 1.2.2 | 126 | 1/27/2026 |
| 1.2.0 | 214 | 1/24/2026 |
| 1.1.5 | 129 | 1/22/2026 |
| 1.1.4 | 272 | 1/10/2026 |
Version 3.2.0 - The JS bridge now serves as a real static web asset at _content/CheapAvaloniaBlazor/cheap-blazor-interop.js: the packaged build props previously dropped the SDK-generated static web assets registration (NU5118), so that path returned 404 from packaged consumers. JavaScriptBridgeExtractor and the embedded-resource serving fallbacks are removed; public classes PrefixedEmbeddedFileProvider and EmbeddedResourceFileInfo are gone and the extracted root-path copy (/cheap-blazor-interop.js) no longer exists - reference the _content path, which all templates and docs already use (breaking). blazor.web.js extraction now picks the cache version matching the app's runtime and refreshes stale copies after a .NET update. Static files serve correctly regardless of the launch working directory. New xUnit test suite guards the packaging wiring.