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

OrdersForm.cs (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

MainWindow.xaml.cs (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

MainWindow.axaml.cs (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 StackPanel or a Board of 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

The WinForms showcase window, title bar ArionUI Showcase (WinForms), dark theme: side bar with search and scene list, a header with drop-downs and switches, the Dashboard scene in the middle and the scene card on the right. The WinForms showcase window, title bar ArionUI Showcase (WinForms), light theme: side bar with search and scene list, a header with drop-downs and switches, the Dashboard scene in the middle and the scene card on the right.
The showcase on the WinForms host, “Dashboard” scene. Brand, search, header, status line and scene card are ArionUI controls on six 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.