Controls
Drawn controls for the parts of a window that are not a grid: buttons, a text box, check boxes, switches, a slider, a drop-down button, labels, panels and a free drawing surface — styled by the same sheets as the board, focusable, and announced to screen readers.
Preview Part of ArionUI Core (ArionUI.Presentation.Controls). This is about a dozen controls, not a complete control library — what is missing is listed below.
Built today
| Control | What it is |
|---|---|
Button | Text and Click; Space and Enter press it. The theme draws it quiet; the classes primary and neutral give the other two looks, or Visual sets one in code. |
TextBox | One line: caret, selection by mouse and keyboard, a word or everything by double and triple click, clipboard, undo and redo inside the field. Changed, Committed (Enter), Cancelled (Escape); a placeholder through Field.Placeholder. |
CheckBox, ToggleSwitch | Text, Value and Toggle; Space toggles. The switch's knob is animated. |
ArionSlider | Minimum, Maximum, Step, LargeStep, Value, Changed, and a Format for what a screen reader hears. |
DropDownButton | The closed state of a drop-down. Open receives the button's rectangle and opens whatever the application wants there — a menu, a list. |
Label | Text from a Func<string>, with MaxLines for wrapping and a Style of its own, or the font of the tile around it. |
Drawing | A free drawing surface: Paint gets the render surface and the rectangle. |
Separator, Spacer, MenuRow | A hairline, an empty stretch, and a focusable row with your own drawing that activates on click or Enter. |
StackPanel | Children vertical or horizontal (Horizontal), each Auto, Fill or a fixed size along the main axis, with Gap and MainPadding. |
ScrollPanel | One child, scrolled vertically with drawn scroll bars; BringIntoView, ScrollTo. |
Card | A frame with fill, border, radius, padding and shadow around one child. |
Board, ViewTile, ElementTile | The grid of tracks, any view as a tile, and a single cell element — sparkline, donut, bullet, progress — as a tile. See Board. |
A small form
Controls read the application's state through Func<> and write it through Action: there is no binding layer between them and your objects. A control asks for its text when it draws, so it always shows the current value.
using ArionUI.Presentation.Controls; // TextBox, CheckBox, ToggleSwitch, ArionSlider, Button
var name = new TextBox { Id = "name", Spoken = () => "Name", Committed = () => Log("name entered") };
var weekly = new CheckBox
{
Id = "weekly",
Text = () => "Send me the weekly report",
Value = () => settings.Weekly,
Toggle = () => settings.Weekly = !settings.Weekly,
};
var alerts = new ToggleSwitch
{
Text = () => "Alerts",
Value = () => settings.Alerts,
Toggle = () => settings.Alerts = !settings.Alerts,
};
var volume = new ArionSlider
{
Minimum = 0,
Maximum = 100,
Step = 5,
Value = () => settings.Volume,
Changed = v => settings.Volume = v,
Format = v => $"{v:0} %",
};
var save = new Button
{
Id = "save",
Text = () => "Save",
Classes = ["primary"], // the theme's primary look
EnabledWhen = () => name.Text.Length > 0,
Click = Save,
};Laid out with a stack, inside a scrolling card:
var form = new StackPanel { Gap = 10 }
.Add(new Label { Text = () => "Newsletter" })
.Add(name)
.Add(weekly)
.Add(new Separator())
.Add(new StackPanel { Horizontal = true, Gap = 12 }
.Add(new Spacer(), StackPanel.Fill) // pushes the button right
.Add(save, cross: 30));
var panel = new Card(new ScrollPanel(form)) { Padding = 16, CornerRadius = 10 };On a board, a form is usually a nested board instead — labels in an auto column, fields in a star column — as on Board.
What every control has
Id- Names the control for focus (
initialFocusId), for the dispatch and for tests. A control without one gets an id from its position. AccessibleName,Spoken- What a screen reader calls it, when its own text is not enough.
EnabledWhen,VisibleWhen- Asked each time; a disabled control takes no input and gets the
Disabledstate for the style sheets. Classes- The control's style classes, which the rules of the sheets select. See Styling.
ExplainStyle(states)- What the cascade weighed for the control's face in those states.
Focus, keyboard and screen readers
A ControlHost holds a tree of controls: focus follows the click, Tab walks the tree in order, the pointer is captured while a button is held, and the focused control draws its focus ring. ControlDispatch carries keys, text, the clipboard and the caret in from the host, and lets Tab move into and out of the tree from the window around it. Each control has a role — button, text, check box, slider, drop-down, static text, group, table — and a value where it has one; the hosts expose them to screen readers — UI Automation on Avalonia and WPF, MSAA on WinForms. The candidate window of an input method is placed at the caret; text being composed is not shown in the field (no IME pre-edit).
Drop-downs and menus today
A DropDownButton opens what the application gives it. With MenuOverlayContent that is a menu, opened as a pane of the surface that shows the button:
using ArionUI.Presentation.Overlay; // MenuOverlayContent, MenuItem, OverlayPlacement
var pick = new DropDownButton
{
Text = () => region,
Open = anchor => surface.OpenPane(
new MenuOverlayContent(
[
new MenuItem("North", () => region = "North"),
new MenuItem("South", () => region = "South"),
MenuItem.Separator(),
new MenuItem("All regions", () => region = "All"),
],
surface.MeasureText),
anchor,
OverlayPlacement.BelowStart),
};Panes open in a stack with light dismiss: a click outside closes them. The same pane stack carries the grid's own menus, the calendar and the filter lists. A combo box that holds a value, filters as you type or accepts free text is not built yet — it is on the list below.
Drawing your own
var gauge = new Drawing
{
Height = 48,
Paint = (s, r) =>
{
s.DrawRoundedRect(r, 6, Palette.HeaderFill, Rgba.Transparent, 0);
s.DrawRoundedRect(r with { Width = r.Width * 0.62 }, 6, Palette.Accent, Rgba.Transparent, 0);
},
AccessibleName = () => "Load 62 percent",
};Palette reads the current theme, so the drawing follows a theme switch. For a micro chart there is no need to draw: ElementTile shows a column's cell element on its own, with the tooltip the column has in a table.
var spark = new ElementTile(
Column.Sparkline<IReadOnlyList<double>>("Revenue", h => h, v => v.ToString("N1") + " k"),
history)
{
Height = 44,
};Controls go on a board, into a pane, or — outside any grid — onto an ArionControlSurface in a WinForms, WPF or Avalonia window.
Planned
What a complete application UI needs and ArionUI does not have yet. The decision to build all of it is made; there are no dates.
Planned Controls and surfaces
- Tab control Almost every business form groups its fields on tabs.
- Radio buttons and option groups An exclusive choice with arrow-key navigation and the right screen-reader role cannot be faked with check boxes.
- A combo box as a control: a value, type-ahead, editable Today a drop-down button opens a menu; a form field needs a value it holds and a list you can type into.
- Multi-line text box Notes, comments and addresses do not fit on one line.
- Numeric up-down and date picker as stand-alone controls The grid already edits numbers, masks and dates in its cells; a form needs the same editors outside a grid.
- Menu bar, toolbar and context menus on controls A menu exists as a pane the application opens itself; a window needs a menu bar at its top edge and context menus on any control.
- Draggable splitters, and docking later Users resize the regions of a working window; today a layout has fixed edges and a centre.
- Image control Logos, photos and icons are part of most screens; today they are drawn by hand in a drawing control.
- Tooltips on controls A button with only an icon needs a tooltip to explain itself.
- A validation state on controls: an error text and an Invalid state for style sheets A form has to show which field is wrong and why, in the theme's colours.
No dates: these are decided, not scheduled. The whole list is on the roadmap.
