Goal
Why this matters
Prerequisites
Avalonia ships multiple desktop backends; AppBuilder.UsePlatformDetect() selects the correct platform at runtime. Understanding the differences helps when you tweak options or debug native interop.
| Platform | Backend type | Namespace | Notes |
|---|---|---|---|
| Windows | Win32Platform |
Avalonia.Win32 |
Win32 windowing with optional WinUI composition, ANGLE/OpenGL bridges, tray icon helpers. |
| Windows/macOS | AvaloniaNativePlatform |
Avalonia.Native |
Shared native host (AppKit on macOS). Used for windowless scenarios and for macOS desktop builds. |
| Linux (X11) | X11Platform |
Avalonia.X11 |
Traditional X11 windowing; integrates with FreeDesktop protocols. |
| Linux portals | FreeDesktopPlatform |
Avalonia.FreeDesktop |
Supplements X11/Wayland with portal services (dialogs, notifications). |
Startup options customize each backend:
AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions
{
RenderingMode = new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software },
CompositionMode = new[] { Win32CompositionMode.WinUIComposition, Win32CompositionMode.RedirectionSurface },
OverlayPopups = true
})
.With(new MacOSPlatformOptions
{
DisableDefaultApplicationMenuItems = false,
ShowInDock = true
})
.With(new X11PlatformOptions
{
RenderingMode = new[] { X11RenderingMode.Glx, X11RenderingMode.Software },
UseDBusMenu = true,
WmClass = "MyAvaloniaApp"
});
These options map to platform implementations in Avalonia.Win32, Avalonia.Native, and Avalonia.X11. Tune them when enabling extended client area, portals, or GPU interop.
<Window xmlns="https://github.com/avaloniaui"
x:Class="MyApp.MainWindow"
Width="1024" Height="720"
CanResize="True"
SizeToContent="Manual"
WindowStartupLocation="CenterScreen"
ShowInTaskbar="True"
Topmost="False"
Title="My App">
</Window>
Properties:
WindowState: Normal, Minimized, Maximized, FullScreen.CanResize, CanMinimize, CanMaximize control system caption buttons.SizeToContent: Manual, Width, Height, WidthAndHeight (works best before window is shown).WindowStartupLocation: Manual (default), CenterScreen, CenterOwner.ShowInTaskbar: show/hide taskbar/dock icon.Topmost: keep above other windows.Persist position/size between runs:
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
if (LocalSettings.TryReadWindowPlacement(out var placement))
{
Position = placement.Position;
Width = placement.Width;
Height = placement.Height;
WindowState = placement.State;
}
}
protected override void OnClosing(WindowClosingEventArgs e)
{
base.OnClosing(e);
LocalSettings.WriteWindowPlacement(new WindowPlacement
{
Position = Position,
Width = Width,
Height = Height,
State = WindowState
});
}
SystemDecorations="None" removes native chrome; use extend-client-area hints for custom title bars.
<Window SystemDecorations="None"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="PreferSystemChrome"
ExtendClientAreaTitleBarHeightHint="32">
<Grid>
<Border Background="#1F2937" Height="32" VerticalAlignment="Top"
PointerPressed="TitleBar_PointerPressed">
<StackPanel Orientation="Horizontal" Margin="12,0" VerticalAlignment="Center" Spacing="12">
<TextBlock Text="My App" Foreground="White"/>
<Border x:Name="CloseButton" Width="32" Height="24" Background="Transparent"
PointerPressed="CloseButton_PointerPressed">
<Path Stroke="White" StrokeThickness="2" Data="M2,2 L10,10 M10,2 L2,10" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</StackPanel>
</Border>
</Grid>
</Window>
private void TitleBar_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
BeginMoveDrag(e);
}
private void CloseButton_PointerPressed(object? sender, PointerPressedEventArgs e)
{
Close();
}
<Window TransparencyLevelHint="Mica, AcrylicBlur, Blur, Transparent">
</Window>
TransparencyLevelHint = new[]
{
WindowTransparencyLevel.Mica,
WindowTransparencyLevel.AcrylicBlur,
WindowTransparencyLevel.Blur,
WindowTransparencyLevel.Transparent
};
this.GetObservable(TopLevel.ActualTransparencyLevelProperty)
.Subscribe(level => Debug.WriteLine($"Transparency: {level}"));
Platform support summary (subject to OS version, composition mode):
Design for fallback: ActualTransparencyLevel may be None--ensure backgrounds look good without blur.
Screens: enumerate monitors (Screens.All, Screens.Primary).Screen.WorkingArea: available area excluding taskbar/dock.Screen.Scaling: per-monitor scale.Window.DesktopScaling: DIP to physical pixel ratio for positioning.TopLevel.RenderScaling: DPI scaling for rendering (affects pixel alignment).Center on active screen:
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
var currentScreen = Screens?.ScreenFromWindow(this) ?? Screens?.Primary;
if (currentScreen is null)
return;
var frameSize = PixelSize.FromSize(ClientSize, DesktopScaling);
var target = currentScreen.WorkingArea.CenterRect(frameSize);
Position = target.Position;
}
Handle scaling changes when moving between monitors:
ScalingChanged += (_, _) =>
{
// Renderer scaling updated; adjust cached bitmaps if necessary.
};
System.Windows.Shell interop or community packages.WindowNotificationManager or Windows toast (via WinRT APIs).TransparencyLevelHint and ensure the OS supports it; consider theme-aware backgrounds.Win32PlatformOptions exposes rendering toggles (RenderingMode, CompositionMode, OverlayPopups). Keep Software in the list as a fallback for Remote Desktop.TryGetPlatformHandle() to retrieve HWNDs when integrating with native libraries; avoid depending on internal WindowImpl types.NativeMenuBar (Chapter 13).NativeMenuBar.Menu can include items that appear in dock menu.AvaloniaNativeMenuCommands or handle native application events.WindowState.FullScreen works, but ensure custom chrome still accessible.MacOSPlatformOptions lets you hide dock icons, disable the default menu items, or reuse an existing NSApplication delegate.AvaloniaNativeRenderingMode with a UseSkia configuration so you always include Software fallback alongside Metal/OpenGl for older GPUs.RenderScaling for the active monitor.X11PlatformOptions controls GLX/EGL fallbacks, DBus menus, and IME support; pair it with Avalonia's FreeDesktop portal helpers when running inside Flatpak/Snap.WmClass (on X11PlatformOptions) to integrate with desktop launchers and icon themes.Avalonia renders through Skia; each backend exposes toggles for GPU acceleration and composition. Tune them to balance visuals versus compatibility.
| Platform | Rendering options | When to change |
|---|---|---|
Windows (Win32PlatformOptions) |
RenderingMode (AngleEgl, Wgl, Vulkan, Software), CompositionMode (WinUIComposition, etc.), GraphicsAdapterSelectionCallback, WinUICompositionBackdropCornerRadius |
Choose ANGLE + WinUI for blur effects, fall back to software for remote desktops, pick dedicated GPU in multi-adapter rigs. |
macOS (AvaloniaNativePlatformOptions) |
RenderingMode (Metal, OpenGL, Software) |
Prefer Metal on modern macOS; include Software as fallback for virtual machines. |
Linux (X11PlatformOptions) |
RenderingMode (Glx, Egl, Vulkan, Software), GlxRendererBlacklist, UseDBusMenu, UseDBusFilePicker |
Disable GLX on problematic drivers, force software when GPU drivers are unstable. |
UseSkia accepts SkiaOptions for further tuning:
AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new SkiaOptions
{
MaxGpuResourceSizeBytes = 128 * 1024 * 1024, // cap VRAM usage
UseOpacitySaveLayer = true
})
.UseSkia()
.LogToTrace();
Inside a window you can inspect the actual implementation for diagnostics:
if (TryGetPlatformHandle() is { Handle: var hwnd, HandleDescriptor: "HWND" })
Debug.WriteLine($"HWND: 0x{hwnd.ToInt64():X}");
Log area Avalonia.Rendering.Platform reports which backend was selected; capture it during startup when debugging GPU-related issues.
dotnet publish -r win-x64 --self-contained or MSIX via dotnet publish /p:PublishTrimmed=false /p:WindowsPackageType=msix. Bundle ANGLE DLLs (libEGL.dll, libGLESv2.dll) and d3dcompiler_47.dll when using GPU composition; ship vc_redist prerequisites for older OS versions..app bundle; codesign and notarize for distribution (dotnet publish -r osx-x64 --self-contained followed by bundle packaging via Avalonia templates or scripts). Include libAvaloniaNative.dylib, ensure Info.plist declares NSHighResolutionCapable, and register custom URL schemes if you rely on ILauncher.libAvaloniaNative.so, libSkia) are present. Flatpak portals rely on xdg-desktop-portal; declare it as a runtime dependency and verify DBus access so storage pickers keep working.Reference docs: Avalonia publishing guide (docs/publish.md).
ApplicationLifetime.Windows (desktop only).IClassicDesktopStyleApplicationLifetime.Exit to exit the app.Screens.All and setting Position accordingly.| Issue | Fix |
|---|---|
| Window blurry on high DPI | Use vector assets; adjust RenderScaling; ensure UseCompositor is default |
| Transparency ignored | Check ActualTransparencyLevel; verify OS support; remove conflicting settings |
| Custom chrome drag fails | Ensure BeginMoveDrag only on left button down; avoid starting drag from interactive controls |
| Incorrect monitor on startup | Set WindowStartupLocation or compute position using Screens before showing window |
| Linux packaging fails | Include libAvaloniaNative.so dependencies; use Avalonia Debian/RPM packaging scripts |
Win32RenderingMode, X11RenderingMode, etc.) starts under different option combinations and document the impact on transparency and input latency.Window.cs, TopLevel.csWindowTransparencyLevel.csScreens.csWindow.cs lines around ExtendClientArea propertiesClassicDesktopStyleApplicationLifetime.csWin32PlatformOptions, AvaloniaNativePlatformExtensions, X11Platform.csSkiaOptionsScreens and scaling info?What's next