AI Windows: Blazor Windows

AI-first map of Blazor window framework APIs and window hosting.

Blazor Windows Discovery Map

Reference map for Blazor-backed native windows, WebView2 hosts, dialog windows, Razor view resolution, custom title bars, and window automation.

Use core/blazor.md for shared Razor component infrastructure such as BlazorReactiveComponent, ReactiveSection, dynamic view resolution, content repository, and JS utilities.

Use osd/screen-overlay.md for click-through desktop annotations and nuget/imgui-sdk.md for optional ImGui windows.

User Intents

  • Open a script-owned Razor/Blazor dialog.
  • Host a Razor component in a native window.
  • Understand when a C# Overlay is different from a script-created window.
  • Configure size, position, owner, transparency, topmost, no-activate, or click-through behavior.
  • Access the owning window from inside a Razor component.
  • Register or resolve Razor views by DataContext.
  • Open WebView DevTools.
  • Load CSS/JavaScript/assets into the hosted WebView.
  • Suppress WebView/browser shortcuts such as Ctrl+A, Ctrl+P, and F5 while keeping Blazor shortcut handlers active.
  • Use reactive Razor components for toggles and script-facing UI.
  • Open complex editor/tool windows from a large script app.

Concept Model

  • IBlazorWindow is a native WPF/WinForms window hosting Blazor content.
  • ViewType is the Razor component type.
  • DataContext is passed to the hosted view.
  • IBlazorWindowController owns window state and operations.
  • IBlazorWindowNativeController owns native handle/rectangle operations.
  • IBlazorWindowAccessor exposes the owning window inside a component.
  • BlazorContentPresenter resolves dynamic component content.
  • WebView2 is the embedded browser that renders the Razor/HTML/CSS/JS surface.
  • C# Overlay is a preconfigured script-hosted Blazor surface controlled by aura overlay settings.
  • A script-created Blazor window is opened explicitly by script/app code.
  • Blazor windows are native windows; use OSD/screen-overlay maps for click-through screen annotations.

API Details

  • IBlazorWindow - main window contract; Show, ShowDialog, Close, ShowDevTools, ViewType, DataContext, Container, AdditionalFiles, AdditionalFileProvider, RegisterFileProvider.
  • IBlazorWindowController - visual and behavior properties.
  • IBlazorWindowNativeController - GetWindowHandle, GetWindowRect, SetWindowRect.
  • IDialogWindowUnstableScriptingApi - script-facing helper for dialog windows.
  • IBlazorWindowAccessor - injectable owner-window accessor.
  • IBlazorViewRepository, IBlazorViewRegistrator, BlazorViewAttribute - DataContext-based view resolution.
  • BlazorReactiveComponent / BlazorReactiveComponent<T> - common base for reactive Razor components.
  • IBlazorContentRepository - app/global list of Blazor CSS/JS files inserted into hosted WebViews.
  • IRootContentFileProvider - root/static-web-asset lookup for files referenced by Blazor content.
  • IScriptFileProvider - script/project resource file provider.
  • ScriptEmbeddedResourceFileProvider - exposes embedded script assembly resources through IScriptFileProvider.
  • ScriptBlazorWindowConfigurator - registers the script file provider with script-owned Blazor windows.
  • IJsPoeBlazorUtils.LoadCss(...) - load CSS into the WebView at runtime.
  • IJsPoeBlazorUtils.LoadScript(...) - load plain JavaScript into the WebView at runtime.
  • IJsPoeBlazorUtils.SuppressWellKnownBrowserShortcuts(...) - explicit opt-in DOM listener for blocking common browser/WebView default shortcuts. It returns an async-disposable handle and does not stop propagation by default.
  • HeadContent - declarative Blazor way to add CSS/head content.
  • ToggleButton - reusable PoeShared Blazor two-state button control.
  • ScriptBlazorWindowConfigurator - script-window integration point that wires script file providers/resources into windows.

Practical Concepts

Native file dialogs from a hosted component

For a WPF Open or Save file dialog, capture IBlazorWindowAccessor.Window at command invocation. On that window's Dispatcher, obtain GetWindowHandle() and pass it to PoeShared.Dialogs.Services.IOpenFileDialog.ShowDialog(IntPtr). WpfFileDialog resolves the live WPF Window and uses Microsoft.Win32.OpenFileDialog.ShowDialog(Window). For Save, pass the same owner to ISaveFileDialog.ShowDialog(IntPtr); WpfFileDialog uses Microsoft.Win32.SaveFileDialog.ShowDialog(Window). Cancellation returns no file; successful selection updates LastFile.

The explicit owner must belong to a live WPF window on the calling dispatcher. It does not fall back to an active window or a hidden helper. The parameterless Open API retains its existing owner selection. A backend without explicit-owner support throws NotSupportedException. The parameterless Save API retains its existing owner selection. BT editor LoadFromFileCommand and SaveToFileCommand require the invoking host IBlazorWindow as their command parameter; toolbar and keyboard callers provide their scoped IBlazorWindowAccessor.Window. These services live in PoeShared.Wpf and are host services, not top-level script members.

Automatic ownership and pinning

AutoOwner defaults to true in the native window factory and applies to both Show() and ShowDialog(). At the first automatic presentation the shared core chooses the active registered application window, or the main root configured by the desktop host through BlazorWpfRegistrations.ConfigureMainWindow. If that window is disabled, it follows direct modal blockers within that owner's family. Other families and prewarmed, unshown windows do not become modal owners.

The automatic decision, including no owner, is retained across repeated Show and Hide/Show. This is presentation-time context, not the historical initiator of an asynchronous operation. A nonzero OwnerHandle overrides automatic selection exactly, including when AutoOwner is false. To detach an existing window, hide it, set OwnerHandle = IntPtr.Zero and AutoOwner = false, then show it again. Re-enabling AutoOwner returns to its cached automatic decision, if already made. Ownership must be acyclic.

Topmost remains the caller's requested pin. The native effective pin is that request OR the owner's effective pin, transitively, for modal and non-modal windows. Inheritance never overwrites the requested setting. The same owner supplies initial CenterOwner positioning and modal disable/restore behavior. Repeated Show does not recenter the window.

ShowDialog() also blocks other visible registered windows on its dispatcher, as WPF does. Overlapping modal windows share that blocking lifetime, so closing one does not enable a window still blocked by another. Hide or successful Close/Dispose while a dialog is waiting to open prevents that pending show; a hidden window can subsequently be shown again.

Application dialog callers do not need an owner service, scoped HWND dependency, or owner arguments. Script-created windows, overlays, notifications and independent editor roots disable AutoOwner at their shared creation boundaries. Scripts may opt in explicitly or assign OwnerHandle. A standalone host without a configured root can still use an active registered window; disable AutoOwner for independent SDK roots. The internal registry retains weak controller references and also backs container-scoped AI browser-view discovery.

Set INativeWindow.SuppressActivation before native handle creation to constrain ShowActivated, native activation and explicit Activate. Handle creation can precede Show/ShowDialog. Later changes are ignored with a warning, like AllowsTransparency. The default is false. Hosts can call BlazorWpfRegistrations.ConfigureActivationSuppression(bool) during container setup to apply the property to subsequently resolved native and Blazor windows without replacing scoped Blazor configurators. EyeAuras configures it from --no-activate.

  • Razor component files are normal project files and can have .razor.cs code-behind.
  • Public Razor component classes are easiest for script-created windows.
  • Components should use Blazor dependency injection, parameters, and DataContext; top-level script host members are not component globals.
  • DataContext is the main way to pass a view-model/service object into a hosted component.
  • IBlazorWindowAccessor is the way for a component to reach the owning native window.
  • ShowDevTools() opens WebView developer tools and is useful for CSS/JS debugging.
  • CSS can be inline, loaded declaratively through HeadContent, or loaded programmatically through LoadCss.
  • Bootstrap and the standard EyeAuras/PoeShared Blazor styles are normally registered by the host. Prefer these classes before adding custom CSS.
  • JavaScript can be loaded through LoadScript; module-style JS follows normal Blazor/JS interop rules.
  • Browser/WebView shortcuts that conflict with app UI can be suppressed with IJsPoeBlazorUtils.SuppressWellKnownBrowserShortcuts(...); add data-poe-browser-shortcuts="allow" to DOM subtrees that should opt out.
  • Script embedded resources are exposed through IScriptFileProvider and registered with script-owned Blazor windows by ScriptBlazorWindowConfigurator. They are available by relative path once the provider is attached.
  • Multiple toggles or repeated controls should be backed by explicit properties or item view-models, not copy-pasted hardcoded accessors.

PoeShared.Dialogs.Services.IFolderBrowserDialog.ShowDialog(IntPtr hwndOwner) in PoeShared.Wpf borrows a live originating WPF HWND on that window's dispatcher; explicit implementations validate dispatcher access and never fall back to a foreground/global owner. Unsupported implementations throw; no-argument behavior stays separate. App Razor callers obtain the current HWND from IBlazorWindowAccessor.

CSS And Static Assets

Blazor scoped CSS can be fragile in script-owned or dynamic windows. .razor.css files are usually compiled into an assembly-level *.styles.css file, and the scope attributes may not line up with generated child DOM, dynamic components, third-party component markup, or content loaded through runtime composition.

Preferred order:

  1. Use no custom CSS when possible. Bootstrap and standard EyeAuras/PoeShared styles are already available in normal Blazor windows.
  2. Use normal global CSS for reusable UI shells, dynamic components, and third-party component styling.
  3. Add CSS/JS/images to the specific IBlazorWindow.AdditionalFiles collection when the asset belongs to one window instance.
  4. Add shared CSS/JS through IBlazorContentRepository.AdditionalFiles when it belongs to the app/module as a whole.
  5. Use IJsPoeBlazorUtils.LoadCss(...) or LoadScript(...) when a component must load an asset on demand during its lifecycle.

Per-window files are usually the best fit for mini-apps and script-created dialogs:

csharp
var window = dialogApi.CreateWindow<MyWindow>(viewModel);
window.AdditionalFiles = ImmutableArray.Create<IFileInfo>(
    new RefFileInfo("my-window.css"),
    new RefFileInfo("my-window.js"));
window.Show();

If files come from a provider instead of individual references, attach the provider to the window:

window.RegisterFileProvider(scriptFileProvider).AddTo(window.Anchors);

For global/module-level styles, register files once with the Blazor content repository:

csharp
var repository = container.Resolve<IBlazorContentRepository>();
repository.AdditionalFiles.Add(new RefFileInfo("MyModule.styles.css"));
repository.AdditionalFiles.Add(new RefFileInfo("assets/my-module.css"));

For lifecycle-controlled loading inside a component:

razor
@inject IJsPoeBlazorUtils BlazorUtils

@code {
    protected override async Task OnAfterFirstRenderAsync()
    {
        await base.OnAfterFirstRenderAsync();
        await BlazorUtils.LoadCss("assets/my-window.css");
    }
}

Embedded script resources flow through ScriptEmbeddedResourceFileProvider into IScriptFileProvider. Script-owned windows get that provider registered by ScriptBlazorWindowConfigurator, so Razor, CSS, JS, image, font, and other resource paths can be resolved from the script project or compiled embedded resources without manually copying files next to the application.

Common Flows

Script-Owned Dialog

  1. Create/resolve the dialog-window scripting API in top-level script or app composition code.
  2. Create a window for a Razor component type.
  3. Pass DataContext if the component needs a view-model.
  4. Configure startup location, size, transparency, or behavior before showing.
  5. Add the window to the owning lifetime so it closes when the script/app stops.

C# Overlay UI

  1. Create a C# Overlay aura item.
  2. Put Razor/CSS/JS/component code in the overlay script project.
  3. Use overlay settings for position, style, transparency, and window-vs-overlay behavior.
  4. Use live import/export workflow for fast UI iteration.

Load Assets

  1. Add CSS/JS/images as embedded resources in the script project.
  2. Reference images/videos by relative path from Razor.
  3. Prefer IBlazorWindow.AdditionalFiles for CSS/JS that belongs to one window instance.
  4. Use IBlazorContentRepository.AdditionalFiles for app/module-wide CSS/JS.
  5. Use HeadContent for simple declarative CSS links, or LoadCss when code controls loading time.
  6. Use LoadScript for plain JavaScript files or URLs.

Suppress Browser Shortcuts

  1. Inject IJsPoeBlazorUtils in the hosted component or shell.
  2. Call SuppressWellKnownBrowserShortcuts() during component initialization.
  3. Store and dispose the returned JsBrowserShortcutSuppressionRef with the component/window lifetime.
  4. Use JsBrowserShortcutSuppressionOptions for custom shortcut lists or propagation behavior.

Embedded Resources In Script Windows

  1. Add files to the script project as embedded resources or project resources.
  2. Let the script runtime expose them through IScriptFileProvider.
  3. For script-created Blazor windows, rely on ScriptBlazorWindowConfigurator or call window.RegisterFileProvider(scriptFileProvider) directly.
  4. Reference the resource by its normalized relative path from Razor, CSS, JS, AdditionalFiles, or LoadCss / LoadScript.

Prefer

  • Prefer IDialogWindowUnstableScriptingApi for script-owned dialogs.
  • Prefer IBlazorWindowAccessor inside hosted components.
  • Prefer BlazorReactiveComponent when the component needs reactive refresh helpers.
  • Prefer DataContext/view-models for non-trivial components.
  • Prefer embedded resources and relative paths for CSS/JS/images shipped with a mini-app.
  • Prefer Bootstrap and built-in EyeAuras/PoeShared classes before adding custom CSS.
  • Prefer IBlazorWindow.AdditionalFiles for per-window CSS/JS assets.
  • Prefer IBlazorContentRepository.AdditionalFiles for app/module-wide CSS/JS.
  • Prefer normal global CSS over scoped .razor.css when styling dynamic components, child component DOM, or third-party component markup.
  • Prefer SuppressWellKnownBrowserShortcuts(...) over one-off page-level scripts when a WebView app needs to block browser defaults.
  • Prefer recipes/bot-memory-imgui-interface.md when Blazor windows are part of a larger ImGui-rooted script app.
  • Prefer osd/screen-overlay.md for drawing over the desktop.
  • Prefer nuget/imgui-sdk.md for ImGui-specific tools.

Avoid

  • Avoid manually creating WPF/WinForms shells for Razor content.
  • Avoid changing creation-time transparency after the native window exists.
  • Avoid assuming a Razor component can access its owner without accessor.
  • Avoid assuming top-level script host members are available directly in Razor components.
  • Avoid using Blazor Windows as the first choice for simple screen annotations; use the OSD/screen-overlay APIs for that.
  • Avoid remote CSS/JS dependencies when a mini-app should work offline or be portable.
  • Avoid relying on scoped .razor.css for dynamic windows when the generated *.styles.css file is not registered, or when the final DOM is generated by child/third-party components.
  • Avoid page-specific global CSS names without a stable prefix.
  • Avoid native/global keyboard interception when the issue is only browser DOM shortcut behavior inside a Blazor WebView.

Research Anchors

  • IBlazorWindow, IBlazorWindowController, IBlazorWindowNativeController, IDialogWindowUnstableScriptingApi, IBlazorWindowAccessor, BlazorContentPresenter, IBlazorViewRepository, BlazorViewAttribute, ShowDevTools, BlazorReactiveComponent, IJsPoeBlazorUtils, LoadCss, LoadScript, SuppressWellKnownBrowserShortcuts, HeadContent, ToggleButton, IBlazorContentRepository, IRootContentFileProvider, IScriptFileProvider, ScriptEmbeddedResourceFileProvider, ScriptBlazorWindowConfigurator, AdditionalFiles, AdditionalFileProvider, RegisterFileProvider.

Search Synonyms

  • Blazor window
  • Razor window
  • script dialog
  • WebView2 window
  • C# Overlay
  • hosted Razor component
  • Razor code-behind
  • HeadContent
  • LoadCss
  • LoadScript
  • SuppressWellKnownBrowserShortcuts
  • browser shortcut suppression
  • Ctrl+A
  • Ctrl+P
  • AdditionalFiles
  • AdditionalFileProvider
  • RegisterFileProvider
  • IBlazorContentRepository
  • IScriptFileProvider
  • embedded resources
  • scoped CSS
  • razor.css
  • styles.css
  • BlazorReactiveComponent
  • ToggleButton
  • custom title bar
  • click-through window
  • transparent window
  • WebView DevTools
  • osd/screen-overlay.md
  • core/blazor.md
  • recipes/bot-memory-imgui-interface.md
  • nuget/imgui-sdk.md
  • scripting/project-workflow.md
  • scripting/references-and-resources.md
  • scripting/runtime.md
  • core/app-runtime-contexts.md