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

ControlWhat it is
ButtonText 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.
TextBoxOne 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, ToggleSwitchText, Value and Toggle; Space toggles. The switch's knob is animated.
ArionSliderMinimum, Maximum, Step, LargeStep, Value, Changed, and a Format for what a screen reader hears.
DropDownButtonThe closed state of a drop-down. Open receives the button's rectangle and opens whatever the application wants there — a menu, a list.
LabelText from a Func<string>, with MaxLines for wrapping and a Style of its own, or the font of the tile around it.
DrawingA free drawing surface: Paint gets the render surface and the rectangle.
Separator, Spacer, MenuRowA hairline, an empty stretch, and a focusable row with your own drawing that activates on click or Enter.
StackPanelChildren vertical or horizontal (Horizontal), each Auto, Fill or a fixed size along the main axis, with Gap and MainPadding.
ScrollPanelOne child, scrolled vertically with drawn scroll bars; BringIntoView, ScrollTo.
CardA frame with fill, border, radius, padding and shadow around one child.
Board, ViewTile, ElementTileThe 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.

Settings.cs
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:

The form
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 Disabled state 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).

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:

A choice from a menu
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

A gauge
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.

A sparkline as a control
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.