CheapAvaloniaBlazor 1.0.72
See the version list below for details.
dotnet add package CheapAvaloniaBlazor --version 1.0.72
NuGet\Install-Package CheapAvaloniaBlazor -Version 1.0.72
<PackageReference Include="CheapAvaloniaBlazor" Version="1.0.72" />
<PackageVersion Include="CheapAvaloniaBlazor" Version="1.0.72" />
<PackageReference Include="CheapAvaloniaBlazor" />
paket add CheapAvaloniaBlazor --version 1.0.72
#r "nuget: CheapAvaloniaBlazor, 1.0.72"
#:package CheapAvaloniaBlazor@1.0.72
#addin nuget:?package=CheapAvaloniaBlazor&version=1.0.72
#tool nuget:?package=CheapAvaloniaBlazor&version=1.0.72
๐ CheapAvaloniaBlazor
Build cross-platform desktop applications with the web development stack you already know.
Combine Blazor Server + Your Choice of UI Framework (currently MudBlazor, more options coming) + 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.
โจ Why CheapAvaloniaBlazor?
The Problem: Building cross-platform desktop apps traditionally requires learning different UI frameworks for each platform or dealing with complex native interop.
The Solution: Use your existing web development skills (HTML, CSS, Blazor, C#) to build real desktop applications with native capabilities.
๐ฏ Perfect For:
- Web developers transitioning to desktop development
- Rapid prototyping of desktop applications
- Line-of-business apps requiring native file system access
- Cross-platform tools that need to run on Windows, Linux, and macOS
- Blazor developers wanting to break free from browser limitations
- Teams wanting UI framework flexibility (MudBlazor now, more options coming)
๐ฆ Installation Options
Option A: Command Line (VS Code/Terminal Users)
# Create a new console project (CheapAvaloniaBlazor handles the desktop setup)
dotnet new console -n MyDesktopApp
cd MyDesktopApp
# Add CheapAvaloniaBlazor package
dotnet add package CheapAvaloniaBlazor
Option B: Visual Studio 2022 GUI Users
- File โ New โ Project
- Select "Console App" (.NET 9.0)
- Name your project (e.g., "MyDesktopApp")
- Right-click project โ "Manage NuGet Packages"
- Search for "CheapAvaloniaBlazor" โ Install
Option C: Start with Avalonia Template (Advanced)
# Install Avalonia templates first
dotnet new install Avalonia.ProjectTemplates
# Create Avalonia project, then add CheapAvaloniaBlazor
dotnet new avalonia.app -n MyDesktopApp
cd MyDesktopApp
dotnet add package CheapAvaloniaBlazor
# Note: You'll need to integrate with existing Avalonia setup
๐ก Why start with Console App? CheapAvaloniaBlazor handles all the desktop framework setup for you! No need for complex Avalonia/Blazor project templates - just add the package and you're ready to build.
๐ Quick Start (5 Minutes)
Note for Visual Studio Users: Create folders and files using Solution Explorer โ Right-click project โ Add โ New Folder/Item
1. Update Project File
Edit your .csproj
file to use the Web SDK (includes MVC and Blazor support):
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CheapAvaloniaBlazor" Version="1.0.68" />
</ItemGroup>
</Project>
2. Replace Program.cs
using CheapAvaloniaBlazor.Hosting;
namespace MyDesktopApp;
class Program
{
[STAThread]
public static void Main(string[] args)
{
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.AddMudBlazor();
// Add your services
builder.Services.AddScoped<IMyService, MyService>();
// Run the app - all Avalonia complexity handled by the package
builder.RunApp(args);
}
}
3. Create Components/_Host.cshtml
Visual Studio: Right-click project โ Add โ New Folder โ "Components", then right-click Components โ Add โ New Item โ "Razor Page"
@page "/"
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Desktop App</title>
<base href="~/" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<style>
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
</style>
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
An error has occurred. This application may no longer respond until reloaded.
<a href="" class="reload">Reload</a>
<a class="dismiss">๐</a>
</div>
<script src="_framework/blazor.server.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>
</html>
4. Create App.razor
Visual Studio: Right-click project โ Add โ New Item โ "Razor Component"
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
5. Create Shared/MainLayout.razor
Visual Studio: Right-click project โ Add โ New Folder โ "Shared", then Add โ New Item โ "Razor Component"
@inherits LayoutComponentBase
<MudThemeProvider />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<MudLayout>
<MudAppBar Elevation="1">
<MudIconButton Icon="Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" />
<MudSpacer />
<MudText Typo="Typo.h6">My Desktop App</MudText>
<MudSpacer />
<MudIconButton Icon="Icons.Material.Filled.Settings" Color="Color.Inherit" />
</MudAppBar>
<MudDrawer Open="true" Elevation="1">
<MudDrawerHeader>
<MudText Typo="Typo.h6">Navigation</MudText>
</MudDrawerHeader>
<MudNavMenu>
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="Icons.Material.Filled.Home">Home</MudNavLink>
<MudNavLink Href="/files" Icon="Icons.Material.Filled.Folder">Files</MudNavLink>
</MudNavMenu>
</MudDrawer>
<MudMainContent>
<MudContainer MaxWidth="MaxWidth.Large" Class="my-16 pt-16">
@Body
</MudContainer>
</MudMainContent>
</MudLayout>
6. Create _Imports.razor
Visual Studio: Right-click project โ Add โ New Item โ "Razor Component" โ Name it "_Imports.razor"
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using MudBlazor
@using CheapAvaloniaBlazor
@using CheapAvaloniaBlazor.Services
7. Create Pages/Index.razor
Visual Studio: Right-click project โ Add โ New Folder โ "Pages", then Add โ New Item โ "Razor Component"
@page "/"
@inject IDesktopInteropService Desktop
<PageTitle>Home</PageTitle>
<MudCard>
<MudCardContent>
<MudText Typo="Typo.h4" GutterBottom="true">Welcome to Your Desktop App! ๐</MudText>
<MudText Class="mb-4">
This is a native desktop application built with Blazor and running with full file system access.
</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" @onclick="OpenFileDialog">
Open File Dialog
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Secondary" @onclick="ShowNotification" Class="ml-2">
Show Notification
</MudButton>
</MudCardContent>
</MudCard>
@code {
private async Task OpenFileDialog()
{
var file = await Desktop.OpenFileDialogAsync(new()
{
Title = "Select a file",
Filters = new()
{
new() { Name = "Text Files", Extensions = new[] { "*.txt", "*.md" } },
new() { Name = "All Files", Extensions = new[] { "*.*" } }
}
});
if (file != null)
{
await Desktop.ShowNotificationAsync("File Selected", $"You selected: {Path.GetFileName(file)}");
}
}
private async Task ShowNotification()
{
await Desktop.ShowNotificationAsync("Hello Desktop!", "This is a native desktop notification! ๐");
}
}
๐ง Advanced Configuration
HostBuilder Fluent API
var builder = new HostBuilder()
.WithTitle("Advanced Desktop App")
.WithSize(1400, 900)
.WithPosition(100, 100) // Custom window position
.UsePort(5001) // Custom port
.UseHttps(true) // Enable HTTPS
.EnableConsoleLogging(true) // Enable console logging
.AddMudBlazor(config => // Current: MudBlazor support
{
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomLeft;
})
// .AddRadzen() // Coming: Radzen components
// .AddTelerik() // Coming: Telerik UI
// .AddBootstrap() // Coming: Bootstrap components
.AddHttpClient("API", client => // Named HTTP client
{
client.BaseAddress = new Uri("https://api.example.com");
})
.ConfigureOptions(options => // Advanced options
{
options.EnableDevTools = true;
options.EnableContextMenu = false;
options.Resizable = true;
});
// Add custom services
builder.Services.AddSingleton<IDataService, DataService>();
builder.Services.AddScoped<IFileManager, FileManager>();
var window = builder.Build();
window.Run();
Desktop Interop Features
@inject IDesktopInteropService Desktop
// File System Operations
var selectedFile = await Desktop.OpenFileDialogAsync();
var saveLocation = await Desktop.SaveFileDialogAsync();
var folder = await Desktop.OpenFolderDialogAsync();
// File I/O
var content = await Desktop.ReadFileAsync("document.txt");
await Desktop.WriteFileAsync("output.txt", Encoding.UTF8.GetBytes("Hello Desktop!"));
var exists = await Desktop.FileExistsAsync("somefile.txt");
// Window Management
await Desktop.MinimizeWindowAsync();
await Desktop.MaximizeWindowAsync();
await Desktop.SetWindowTitleAsync("New Title");
var state = await Desktop.GetWindowStateAsync();
// System Integration
await Desktop.OpenUrlInBrowserAsync("https://github.com");
await Desktop.ShowNotificationAsync("Title", "Message");
// Clipboard Operations
var clipboardText = await Desktop.GetClipboardTextAsync();
await Desktop.SetClipboardTextAsync("Copied from desktop app!");
// Get system paths
var appDataPath = await Desktop.GetAppDataPathAsync();
var documentsPath = await Desktop.GetDocumentsPathAsync();
๐ Project Structure
MyDesktopApp/
โโโ Program.cs # Application entry point
โโโ App.razor # Blazor router configuration
โโโ Components/
โ โโโ _Host.cshtml # Blazor host page (contains full HTML)
โโโ Pages/
โ โโโ Index.razor # Home page
โ โโโ Files.razor # File management page
โโโ Shared/
โ โโโ MainLayout.razor # Main application layout
โโโ wwwroot/ # Static web assets
โ โโโ css/
โโโ Services/ # Your business logic
โโโ IMyService.cs
๐ Architecture & Integration
How It Works
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Avalonia โ โ Blazor Server โ โ Photino โ
โ (Desktop โโโโโบโ (Web UI & โโโโโบโ (WebView โ
โ Framework) โ โ Components) โ โ Hosting) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โฒ โฒ โฒ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Native OS โ โ MudBlazor โ โ File System โ
โ Integration โ โ (Material UI) โ โ Access โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
Technology Stack
- UI Layer: Blazor Server + Razor Pages + MudBlazor components
- Desktop Framework: Avalonia (cross-platform window management)
- WebView Host: Photino.NET (native webview embedding)
- Backend: ASP.NET Core (dependency injection, services, middleware)
- Interop: Custom desktop services (file dialogs, notifications, etc.)
๐ ๏ธ Build & Deployment
Development
# 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
Production Builds
# 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
Distribution
# Windows
MyDesktopApp.exe
# Linux
./MyDesktopApp
# macOS
./MyDesktopApp
๐ System Requirements
Runtime Requirements
- .NET 9.0 or later
- Windows 10+ โ (Tested)
- Linux with WebKit โ ๏ธ (Untested - on roadmap)
- macOS 10.15+ โ ๏ธ (Untested - on roadmap)
Development Requirements
- Visual Studio 2022 (17.8+) or VS Code
- .NET 9.0 SDK
- C# 13 language features
Package Dependencies
Avalonia 11.3.2+
- Desktop frameworkMudBlazor 8.10.0+
- Material Design componentsPhotino.NET 4.0.16+
- WebView hostingMicrosoft.AspNetCore.Components.Web 9.0.7+
- Blazor components
๐ Troubleshooting
Common Issues & Solutions
๐ซ Build Errors
# Ensure correct .NET version
dotnet --version # Should be 9.0+
# Clear and restore packages
dotnet clean
dotnet restore
dotnet build
๐ซ Window Doesn't Appear
- Check if port 5000/5001 is available
- Verify no firewall blocking local connections
- Look for exceptions in console output
- Try different port:
builder.UsePort(8080)
๐ซ MudBlazor Styles Missing
- Verify CSS reference in
_Layout.cshtml
:<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
- Check browser dev tools for 404 errors
- Ensure
AddMudBlazor()
is called in HostBuilder
๐ซ Platform Compatibility Issues
- Linux/macOS: Currently untested - if you encounter issues, please report them!
- Windows: Fully tested and supported
- Dependencies (Avalonia, Photino) should work cross-platform, but integration not verified
๐ซ Visual Studio Specific Issues
- IntelliSense not working: Rebuild solution (Build โ Rebuild Solution)
- Razor syntax errors: Install latest "ASP.NET and web development" workload
- Package restore issues: Tools โ NuGet Package Manager โ "Clear All NuGet Cache(s)"
- Hot reload not working: Enable "Hot Reload on File Save" in Debug settings
๐ซ File Dialog Not Working
- โ Fixed in v1.0.67+ - File dialogs now work via Avalonia StorageProvider
- Ensure you're using latest version:
dotnet add package CheapAvaloniaBlazor
- Check
IDesktopInteropService
injection - If still having issues, please report - architecture was completely rebuilt for file dialog support
๐ซ Hot Reload Not Working
- Restart application
- Check VS/VS Code Blazor extensions
- Verify project targets .NET 9.0
Debug Mode
var builder = new HostBuilder()
.EnableConsoleLogging(true) // Enable detailed logging
.ConfigureOptions(options =>
{
options.EnableDevTools = true; // Enable browser dev tools
});
๐ฏ Example Applications
File Manager
// Complete file browser with MudBlazor TreeView
@inject IDesktopInteropService Desktop
<MudTreeView Items="FileNodes" @bind-SelectedValue="SelectedFile">
<ItemTemplate>
<MudTreeViewItem @bind-Expanded="@context.IsExpanded"
Value="@context"
Icon="@(context.IsDirectory ? Icons.Material.Filled.Folder : Icons.Material.Filled.InsertDriveFile)">
@context.Name
</MudTreeViewItem>
</ItemTemplate>
</MudTreeView>
System Monitor
// Real-time system information dashboard
<MudGrid>
<MudItem xs="12" md="6">
<MudCard>
<MudCardContent>
<MudText Typo="Typo.h6">CPU Usage</MudText>
<MudProgressLinear Value="@cpuUsage" Color="Color.Primary" />
</MudCardContent>
</MudCard>
</MudItem>
</MudGrid>
Database Browser
// SQLite database browser with data grid
<MudDataGrid Items="@DatabaseRecords" Filterable="true" SortMode="SortMode.Multiple">
<Columns>
<PropertyColumn Property="x => x.Id" Title="ID" />
<PropertyColumn Property="x => x.Name" Title="Name" />
<PropertyColumn Property="x => x.CreatedDate" Title="Created" />
</Columns>
</MudDataGrid>
๐จ Project Status & Roadmap
Current Status: Working Alpha v1.0.68 โ
- โ Core Framework: Avalonia + Blazor + Photino integration
- โ NuGet Package: Published and functional
- โ File System Interop: WORKING - Cross-platform file dialogs via Avalonia StorageProvider
- โ Window Management: Minimize, maximize, resize, title changes
- โ JavaScript โ C# Bridge: Full bidirectional communication with ExecuteScriptAsync
- โ MudBlazor Integration: Full component library support
- โ Clean Architecture: Removed legacy code, optimized for stability
Upcoming Features ๐ฃ๏ธ
- ๐ Testing Framework: Unit and integration test support
- ๐ Cross-Platform Testing: Full compatibility validation on Linux and macOS
- ๐ Alternative WebView Hosts: Additional options beyond Photino.NET
- ๐ Alternative UI Frameworks: Support for Radzen, Telerik, Bootstrap, and other Blazor component libraries
- ๐ Enhanced Documentation: More examples and tutorials
- ๐ Performance Optimization: Startup time and memory usage
- ๐ Plugin System: Extensible architecture
- ๐ Visual Designer: Drag-and-drop UI builder
- ๐ Package Templates:
dotnet new
project templates
Known Limitations โ ๏ธ
- Alpha stage project - some breaking changes possible but architecture now stable
- Currently tested on Windows only - Linux and macOS compatibility validation in progress
- MudBlazor-focused currently - other UI framework integrations planned
- Community support - best-effort basis with active development
- Testing infrastructure in development
๐ค Contributing & Support
Project Status
This is a personal hobby project in alpha stage. The core architecture is now stable (v1.0.67+ with working file dialogs), though some features are still evolving. Limited pull requests accepted for bug fixes and documentation improvements.
How to Help
- ๐ Report Issues: Found a bug? Create an issue
- ๐ฌ Provide Feedback: Share your experience and suggestions
- ๐งช Testing: Try it in your projects and report compatibility issues
- ๐ Documentation: Suggest improvements to examples and guides
Getting Support
- GitHub Issues: Technical problems and bug reports
- Discussions: Questions and community help
- Documentation: Check this README and inline code comments
- Expectations: This is a hobby project - support is provided on a best-effort basis
๐ License & Attribution
MIT License - Use freely in personal and commercial projects.
Built With โค๏ธ Using:
- Avalonia - Cross-platform .NET desktop framework
- Blazor - Build interactive web UIs using C#
- MudBlazor - Material Design component library (current default)
- Photino - Lightweight cross-platform WebView
Future integrations planned: Radzen, Telerik, Bootstrap, Blazorise, and more!
๐ง Special Thanks
Documentation analysis and enhancement by Kowalski - the analytical penguin who never met a codebase he couldn't optimize! ๐ค
๐ Get Started Today!
Ready to build your first cross-platform desktop app with web technologies?
# Create new project
dotnet new console -n MyFirstDesktopApp
cd MyFirstDesktopApp
# Add CheapAvaloniaBlazor
dotnet add package CheapAvaloniaBlazor
# Follow the Quick Start guide above
# Build something amazing! ๐
Questions? Issues? Ideas? Open an issue and share your feedback!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. 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 was computed. 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. |
-
net9.0
- Avalonia (>= 11.3.2)
- Avalonia.Desktop (>= 11.3.2)
- Avalonia.Fonts.Inter (>= 11.3.2)
- Avalonia.Themes.Fluent (>= 11.3.2)
- Microsoft.AspNetCore.Components.Web (>= 9.0.7)
- Microsoft.Extensions.FileProviders.Embedded (>= 9.0.7)
- Microsoft.Extensions.Hosting (>= 9.0.7)
- MudBlazor (>= 8.10.0)
- Photino.NET (>= 4.0.16)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Fixed static web assets using Content with staticwebassets and content PackagePath - resolved JS interop 404 errors