Control surface
ArionControlSurface puts a tree of drawn controls anywhere in a window — docked in a WinForms form, in a WPF panel, as the content of an Avalonia window — not only inside a grid. It is how ArionUI parts move into an existing application one panel at a time.
Preview One control per host, same members on all three: SetRoot, Host, Dispatch, VisualTheme, OpenPane. The WinForms host builds from source and is not a NuGet package yet.
WinForms
using ArionUI.Presentation; // ArionTheme
using ArionUI.Rendering.WinForms; // ArionControlSurface
using Drawn = ArionUI.Presentation.Controls; // WinForms has its own Button and Label
var header = new ArionControlSurface
{
Dock = DockStyle.Top,
Height = 48,
VisualTheme = ArionTheme.Light(),
};
header.SetRoot(new Drawn.StackPanel { Horizontal = true, Gap = 12, MainPadding = 12 }
.Add(new Drawn.Label { Text = () => Text }, Drawn.StackPanel.Fill)
.Add(new Drawn.Button { Id = "save", Text = () => "Save", Classes = ["primary"], Click = Save }, cross: 30));
Controls.Add(header);On WinForms the surface draws its tree on the CPU into one bitmap and puts it on screen in one copy. It has no GL context of its own, so a form can dock many surfaces next to its grids without flicker. The control's BackColor — by default its parent's — is painted behind the tree.
WPF
using ArionUI.Presentation; // ArionTheme
using ArionUI.Rendering.Wpf; // ArionControlSurface
using Drawn = ArionUI.Presentation.Controls; // WPF has its own Button and Label
var surface = new ArionControlSurface { VisualTheme = ArionTheme.Light() };
surface.SetRoot(form, initialFocusId: "name");
formHost.Children.Add(surface);The surface is a FrameworkElement, so it can also be declared in XAML and given its tree from code-behind. initialFocusId names the control that takes the keyboard first.
Avalonia
using ArionUI.Presentation; // ArionTheme
using ArionUI.Rendering.Avalonia; // ArionControlSurface
using Drawn = ArionUI.Presentation.Controls; // Avalonia has its own Button and Label
var surface = new ArionControlSurface { VisualTheme = ArionTheme.Dark() };
surface.SetRoot(form);
window.Content = surface;What the surface does
SetRoot(root, initialFocusId)- Shows a control — usually a
StackPanelor aBoardof controls — and lays it out in the surface's size. Host- The hosted tree's
ControlHost: focus, hover, pointer capture, the caret.Host.SetFocus(id)moves the keyboard to a control,Host.FindControl(id)finds one. Dispatch- Keys, text, the clipboard and Tab into and out of the tree; also what a test or a screen reader uses to read and set values by id.
VisualTheme- The theme the surface draws with; null follows the current theme.
OpenPane(content, anchor, placement),ClosePanes(),HasOpenPane- Opens a pane — a menu, your own content — anchored to a rectangle, as on Controls.
MeasureText(text, style)- Measures text with the surface's renderer; menus take it to size themselves.
A surface shows controls. A board that holds view tiles — a data grid, a chart, a 3D scene in a tile — is shown by a grid control instead: grid.MainView = new BoardView(board) on ArionGrid (Avalonia, WPF) or ArionGridControl (WinForms). That path is virtualized in bands and runs on the GPU like a grid.
The WinForms showcase is built this way

ArionControlSurfaces; the scene list and the dashboard are drawn by ArionGridControls. WinForms only lays out docked panels. Screenshot of the running app (0.1.0-preview.1), title bar left in as evidence.Seen from the other side, this is the modernisation path: an ordinary Form whose panels are replaced, one after the other, by ArionUI surfaces and grids. The guide walks through it: Modernise a WinForms or WPF app.
Planned
Planned For hosting ArionUI in an existing app
- The WinForms host as a NuGet package Without it, a WinForms team has to build ArionUI from source before it can try anything.
- A DataTable source and columns generated from a DataTable Most old forms hold their data in a DataTable; today a grid sees a snapshot of it, not its inserts and deletes.
- BindingSource support, with its current position kept in step with the grid's current item Forms built in the designer navigate through a BindingSource; keeping it means keeping the form's logic.
- Validation from IDataErrorInfo and INotifyDataErrorInfo as a ready edit policy Error texts an application already produces should reach the grid without a second validation layer.
- A view-model bridge: INotifyPropertyChanged repaints a board on the UI thread Today a view model tells the board by hand; MVVM code should not need that line.
- A theme derived from the system colours and the form's font An ArionUI island in an old window should look like it belongs there, not like a different application.
- A WinForms sample: one form with a DataTable, before and after A migration path is only believable when you can open both versions and compare them.
No dates: these are decided, not scheduled. The whole list is on the roadmap.
