Runic.Application.Desktop
0.7.0-preview.6
Runic.Application.Views.Desktop
Additional DetailsRenamed to Runic.Application.Views.Desktop in 0.7.0-preview.7. Namespaces are unchanged; replace the package reference.
dotnet add package Runic.Application.Desktop --version 0.7.0-preview.6
NuGet\Install-Package Runic.Application.Desktop -Version 0.7.0-preview.6
<PackageReference Include="Runic.Application.Desktop" Version="0.7.0-preview.6" />
<PackageVersion Include="Runic.Application.Desktop" Version="0.7.0-preview.6" />
<PackageReference Include="Runic.Application.Desktop" />
paket add Runic.Application.Desktop --version 0.7.0-preview.6
#r "nuget: Runic.Application.Desktop, 0.7.0-preview.6"
#:package Runic.Application.Desktop@0.7.0-preview.6
#addin nuget:?package=Runic.Application.Desktop&version=0.7.0-preview.6&prerelease
#tool nuget:?package=Runic.Application.Desktop&version=0.7.0-preview.6&prerelease
Runic.Application.Desktop
Present Runic Windows and Views with Runic Desktop: native windows, embedded WebViews or browser presentations, and the Runic platform services.
dotnet add package Runic.Application.Desktop --prerelease
dotnet add package Microsoft.Extensions.DependencyInjection
New projects can start with this host: dotnet new runic-app --host desktop.
In a project named MyApp:
using Microsoft.Extensions.DependencyInjection;
using MyApp; // the generated AddRunicViews()
using Runic.Application.Views;
using Runic.Application.Views.Desktop;
using Runic.Desktop;
var services = new ServiceCollection();
services.AddScoped<MainViewModel>();
services.AddRunicViews();
await using var provider = services.BuildServiceProvider();
await using var desktop = await DesktopHost.StartAsync(new DesktopHostOptions
{
// Windows uses WebView2 and macOS WKWebView; Linux selects a toolkit explicitly.
Linux = new() { EmbeddedBackend = LinuxEmbeddedBackend.Gtk3WebKit41 },
});
var windowOptions = new DesktopWindowOptions { Width = 800, Height = 600 };
// Stops at startup when a registration, WebView runtime or window option is missing.
provider.ValidateDesktopWindow<MainViewModel>(desktop, windowOptions).ThrowIfInvalid();
await using var window = await provider.OpenDesktopWindowAsync<MainWindow, MainViewModel>(
desktop,
new DesktopSurfaceOptions { Content = new DesktopContent.Directory(Path.Combine(AppContext.BaseDirectory, "www"), "index.html") },
host => new MainWindow(host),
windowOptions);
window.Presentation.WaitForClose();
public sealed partial class MainWindow(DesktopBridgeWindow<MainViewModel> host)
: RunicWindow<MainViewModel>(host.ViewModel), IAsyncDisposable
{
public DesktopWindow Presentation => host.Presentation;
public ValueTask DisposeAsync() => host.DisposeAsync();
}
Entry points
OpenDesktopWindowAsync<TWindow, TViewModel>creates the Window's DI scope, resolves its ViewModel, opens aDesktopSurfaceand its presentation, and attaches the generated Bridge.ValidateDesktopWindow<TViewModel>checks, before any window opens, that the generated Bridge for the ViewModel is registered and thatDesktopHost.Validateaccepts the window options. It returns every problem as aDesktopDiagnosticwith a stable code and remediation: an errorbridge-not-registered, the Runic Desktop codes, and a warningviewmodel-not-registeredwhen the container does not report the ViewModel throughIServiceProviderIsService. A container can resolve services it does not report, so only the Bridge check fails; a container withoutIServiceProviderIsServiceis not checked.ThrowIfInvalid()throws aDesktopConfigurationException.OpenDesktopWindowAsyncruns the Bridge check itself before it creates a surface, so a missingAddRunicViews()fails with that exception instead of a dependency-injection error. A missing Bridge is logged as event 2001 through the provider'sILoggerFactory.DesktopBridgeWindow<TViewModel>owns the Window's scope, surface, and attachment. It exposesViewModel,Surface,Presentation, andCloseAsync, which stops new operations and waits for accepted ones before releasing the scope. It implementsIBridgeWindow, the lifetime contract shared with the CS-WebUI host, and returns the sameBridgeWindowCloseResult.DesktopBridgeWindow<TViewModel>.NativeOwner(aDesktopNativeOwner) is the presentation'sINativePickerOwner. Pass it to the platform provider that matches the window's backend; no custom adapter is needed:- Windows:
WindowsPlatformProvider.CreateFileDialogs(owner). - macOS:
MacOSPlatformProvider.CreateFileDialogs(owner). - Linux with GTK 3:
LinuxPlatformProvider.CreateFileDialogs(owner). - Linux with GTK 4:
PortalPlatformProvider.CreateFileDialogs(Gtk4PlatformProvider.CreatePortalWindowOwner(owner)).LinuxPlatformProviderparents dialogs through GTK 3, so do not use it with a GTK 4 window.
The owner runs provider callbacks on the window's native thread and becomes unavailable when the window closes or the surface replaces it. A presentation without native dispatch still has an owner, but it reports
IsAvailable == false. Examples are an installed browser after an embedded-window fallback, or a custom host without a native handle. Applications that open aDesktopWindowthemselves create one withnew DesktopNativeOwner(window).- Windows:
DesktopBridgeTransportconnects aDesktopSurfaceto aWindowContentSessiondirectly, for applications that compose a surface themselves.
The surface owns authenticated browser or embedded WebView sessions and
removable capability bindings; the application Window owns its ViewModel scope
and logical View lifetimes. DesktopHostOptions and DesktopWindowOptions
select the browser or embedded backend; the Runic Desktop guide lists the
native prerequisites for each platform.
The package's build targets copy runic-desktop-views.js into www/. Load
webui.js (served by the surface) and runic-desktop-views.js before the
generated client in index.html. The adapter uses the same host-neutral client
contract as the CS-WebUI adapter, and its build defaults match
Runic.Application.CsWebUi, so AddRunicViews() is generated in
<ProjectName>.RunicBridgeComposition.
The First Window on Runic Desktop example is a complete application. See the host selection guide to choose between this host and CS-WebUI.
Automation
Set RUNIC_APPLICATION_CLOSE_AFTER_OPEN=1 to start a template-shaped
application without a user. With it set, OpenDesktopWindowAsync closes every
window it opens, as soon as the presentation has opened and, with
DesktopHostOptions.WaitForConnection, its bridge has connected. Before
closing, it writes:
- a warning to standard error, and event 2002 through a registered
ILoggerFactory, so an inherited setting is visible; RUNIC_APPLICATION_OPENED=<presentation>(for exampleEmbedded, or the browser it fell back to) to standard output.
An application shaped like the runic-app template then sees WaitForClose
return and exits normally. Applications that keep running after a window
closes, or that open further windows, are not meant to use it. This is the
Desktop counterpart of CS-WebUI's RUNIC_APPLICATION_SERVE_ONLY. The template
acceptance check uses it to run the GTK 4 template under Xvfb.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- Microsoft.Web.WebView2 (>= 1.0.4258.31)
- Runic.Application (= 0.7.0-preview.6)
- Runic.Desktop (= 0.7.0-preview.6)
- Runic.Platform.Runtime (= 0.7.0-preview.6)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Runic.Application.Desktop:
| Package | Downloads |
|---|---|
|
Runic.Application.Wpf
Optional WPF child WebView presentation for existing Runic ViewModels. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 0.7.0-preview.6 | 503 | 10/9/2026 | |
| 0.7.0-preview.5 | 158 | 10/9/2026 | |
| 0.7.0-preview.4 | 89 | 10/8/2026 | |
| 0.7.0-preview.3 | 78 | 10/8/2026 | |
| 0.7.0-preview.2 | 83 | 10/7/2026 | |
| 0.7.0-preview.1 | 83 | 10/7/2026 | |
| 0.6.0-preview.1 | 147 | 10/5/2026 | |
| 0.5.0-preview.3 | 78 | 10/1/2026 | |
| 0.5.0-preview.2 | 84 | 9/25/2026 | |
| 0.4.0-preview.1 | 82 | 9/22/2026 | |
| 0.3.0-preview.1 | 93 | 9/11/2026 | |
| 0.2.0-preview.1 | 106 | 9/9/2026 |