This document summarizes the startup-focused Application/Window lifecycle and DX in MewUI. It clarifies the boundary between “before Run” and “after Run”.
This section describes how to configure the platform host and graphics backend before calling Application.Run(...).
MewUI aims to avoid a core-level enum/switch selection for platform/graphics backends.
Instead, each package provides registration and selection to remain trim/AOT-friendly.
Register the platform/backend packages before calling Application.Run(...).
using Aprillz.MewUI;
using Aprillz.MewUI.Backends;
using Aprillz.MewUI.PlatformHosts;
// Detect OS at runtime and register only the platform/backend valid for that OS.
// (In this example: Windows=Win32, Linux=X11, macOS is planned.)
if (OperatingSystem.IsWindows())
{
Win32Platform.Register();
Direct2DBackend.Register(); // or GdiBackend.Register() / OpenGLWin32Backend.Register()
}
else if (OperatingSystem.IsLinux())
{
X11Platform.Register();
OpenGLX11Backend.Register();
}
else if (OperatingSystem.IsMacOS())
{
// TODO: register once macOS platform host/backend are implemented
throw new PlatformNotSupportedException("macOS platform host is not implemented yet.");
}
else
{
throw new PlatformNotSupportedException("Unsupported OS.");
}
Application.Run(mainWindow);If your app is fixed to one platform + one graphics backend (e.g., Windows-only), an Application.Create() chain is the simplest.
Assumptions:
- Your project references the platform/backend packages (so extension methods like
.UseWin32()are available). - The build and package references are already fixed; you are not selecting OS at runtime.
using Aprillz.MewUI;
using Aprillz.MewUI.Backends;
using Aprillz.MewUI.PlatformHosts;
Application.Create()
.UseWin32()
.UseDirect2D()
.Run(mainWindow);Instead of runtime OS branching, you can define symbols via csproj conditions (typically RID/CI publish) and then fix the chain with #if.
This is also convenient for trimming/distribution, because you can structure package references so that each build only includes what it needs.
<PropertyGroup>
<TargetFrameworks>net10.0-windows;net10.0</TargetFrameworks>
<!-- assume CI/publish injects the RID via: dotnet publish -r ... -->
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<!-- dev runs (RID is often empty): use the runtime OS branching path -->
<PropertyGroup Condition="'$(RuntimeIdentifier)' == ''">
<DefineConstants>$(DefineConstants);DEV</DefineConstants>
</PropertyGroup>
<!-- publish/CI (RID is set): fix OS symbols based on RID -->
<PropertyGroup Condition="'$(RuntimeIdentifier)' != '' and $(RuntimeIdentifier.StartsWith('win-'))">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != '' and $(RuntimeIdentifier.StartsWith('linux-'))">
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != '' and $(RuntimeIdentifier.StartsWith('osx-'))">
<DefineConstants>$(DefineConstants);MACOS</DefineConstants>
</PropertyGroup>using Aprillz.MewUI;
using Aprillz.MewUI.Backends;
using Aprillz.MewUI.PlatformHosts;
Application.Create()
#if WINDOWS || DEV
.UseWin32()
.UseDirect2D()
#elif LINUX
.UseX11()
.UseOpenGL()
#elif MACOS
.ThrowPlatformNotSupported("macOS platform host is not implemented yet.")
#else
.ThrowPlatformNotSupported()
#endif
.Run(mainWindow);If you must branch at runtime and still keep a chain-like style, you can use a builder variable and continue chaining after the branch.
- Only configurable before Run: after Run, changing core app settings should throw or be ignored (the policy must be consistent in code).
- Plugin-based registration: platform/backend packages provide Register/selection.
When Application.Run(Window) is called, the flow is:
- Set
Application.Current - Create the PlatformHost and initialize the Dispatcher
- Register and show the Window
- Enter the message loop
var window = new Window()
.Title("Hello")
.Content(new TextBlock().Text("Hello, MewUI"));
Application.Run(window);For ThemeVariant/Accent/ThemeSeed/ThemeMetrics configuration, see:
new Window() only creates the object; no native handle exists yet.
At Window.Show() time:
- Register into Application
- Create backend resources (WindowHandle)
- Raise Loaded
- Perform first Layout & Render
ShowDialogAsync shows a window as a modal dialog and completes when it is closed.
When an owner is provided, the owner window is disabled while the dialog is open (platform dependent).
var dialog = new Window()
.Title("Dialog")
.Content(new TextBlock().Text("Hello from dialog"));
await dialog.ShowDialogAsync(owner: main);var main = new Window()
.Title("Main")
.Content(new TextBlock().Text("Main window"));
var tools = new Window()
.Title("Tools")
.Content(new TextBlock().Text("Tools window"));
main.OnLoaded(() => tools.Show());
Application.Run(main);RenderLoop behavior is controlled via Application.Current.RenderLoopSettings:
Mode:OnRequest/ContinuousTargetFps: 0 means unlimitedVSyncEnabled: controls backend present/swap behavior
Application.Current.RenderLoopSettings.SetContinuous(true);
Application.Current.RenderLoopSettings.VSyncEnabled = false;
Application.Current.RenderLoopSettings.TargetFps = 0; // unlimitedWindow.Close()→ destroy backend → unregister from Application- When the last window closes, the platform loop may exit (platform policy)
Application.Quit()explicitly terminates the loop
- Exceptions on the UI thread are routed to
Application.DispatcherUnhandledException - Unhandled exceptions are treated as fatal by default
Application.DispatcherUnhandledException += e =>
{
try
{
MessageBox.Show(e.Exception.ToString(), "Unhandled UI exception");
}
catch
{
// ignore
}
e.Handled = true;
};- The core flow is: pre-run configuration → Run → message loop
- Theme/RenderLoop should be decided before Run
- A Window only acquires native resources at Show time