Fluent Builders Reference

New to SharpConsoleUI? Start with the Tutorials — they cover WindowBuilder in context from the very first step.

SharpConsoleUI provides fluent builder APIs for creating windows and controls with clean, chainable syntax.

Table of Contents

WindowBuilder

The WindowBuilder class provides a fluent API for creating and configuring windows.

Basic Usage

using SharpConsoleUI.Builders;

var window = new WindowBuilder(windowSystem)
    .WithTitle("My Window")
    .WithSize(80, 25)
    .Centered()
    .Build();

Configuration Methods

Size and Position

.WithSize(width, height)           // Set window dimensions
.AtPosition(x, y)                  // Set window position
.Centered()                        // Center on screen
.WithMinimumSize(width, height)    // Set minimum size constraints

Appearance

.WithTitle(title)                                // Set window title
.WithColors(foreground, background)              // Set colors
.Borderless()                                    // Invisible border (keeps the 1-cell frame; blanks it)
.Frameless()                                     // Truly borderless: content fills the rect, no chrome
.WithPadding(2)                                  // Uniform padding around content (any window)
.WithPadding(horizontal, vertical)              // Horizontal/vertical padding
.WithPadding(new Padding(l, t, r, b))            // Per-side padding
Frameless windows

.Frameless() (sets BorderStyle.Frameless) is a truly borderless window: it reclaims the 1-cell border/title frame so content fills the entire window rect. It is fully chrome-less and non-interactive — no title bar, no drag-to-move handle, no resize edges/grip, and no title buttons. Mouse clicks anywhere go to the content. You can still move/resize it programmatically with SetPosition/SetSize (or your own keyboard handlers); IsMovable/IsResizable keep their values but the (now non-existent) frame can't be grabbed.

This differs from .Borderless()/BorderStyle.None, which keeps the reserved 1-cell frame and simply renders it as blanks (so content still starts one row/column in).

Use .WithPadding(...) to add space around the content (it applies to any window, but is most useful with .Frameless()). The common single-window-app pattern fills the terminal:

new WindowBuilder(windowSystem)
    .Frameless()
    .Maximized()              // fills the desktop; content fills it edge-to-edge
    .WithPadding(1)           // optional breathing room
    .AddControl(myContent)
    .BuildAndShow();

A scrollable frameless window reserves its last content column for the scrollbar when content overflows (so the bar never overlaps content); otherwise content uses the full width.

Behavior

.Resizable(bool)                   // Enable/disable resizing (default: true)
.Movable(bool)                     // Enable/disable moving (default: true)
.Closable(bool)                    // Enable/disable closing (default: true)
.Minimizable(bool)                 // Enable/disable minimizing (default: true)
.Maximizable(bool)                 // Enable/disable maximizing (default: true)
.AsModal()                         // Make window modal

State

.Maximized()                       // Start maximized
.Minimized()                       // Start minimized

Independent Window Thread

.WithAsyncWindowThread(asyncMethod)   // Attach async update loop

The async method receives Window and CancellationToken:

private async Task UpdateWindowAsync(Window window, CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        // Update window content
        await Task.Delay(1000, ct);
    }
}

Event Handlers

.OnKeyPressed((sender, e) => { })        // Key press handler
.OnClosed((sender, e) => { })            // Window closed handler

Templates

// Dialog template (title, size, centered, modal)
.WithTemplate(new DialogTemplate("Title", width, height))

// Tool window template (title, position, size)
.WithTemplate(new ToolWindowTemplate("Tools", new Point(x, y), new Size(w, h)))

Complete Example

var mainWindow = new WindowBuilder(windowSystem)
    .WithTitle("Task Manager")
    .WithSize(80, 25)
    .Centered()
    .WithColors(Color.White, Color.DarkBlue)
    .Resizable()
    .Movable()
    .WithMinimumSize(60, 20)
    .OnKeyPressed((sender, e) =>
    {
        if (e.KeyInfo.Key == ConsoleKey.Escape)
        {
            windowSystem.CloseWindow(sender as Window);
            e.Handled = true;
        }
    })
    .Build();

Panel and Element Builders

Panel builders configure the top and bottom screen-level bars. See the Panel System guide for the full reference.

PanelBuilder

using SharpConsoleUI.Panel;

// Used via ConsoleWindowSystemOptions
var options = new ConsoleWindowSystemOptions(
    TopPanelConfig: panel => panel
        .Left(Elements.StatusText("[bold cyan]My App[/]"))
        .Left(Elements.Separator())
        .Right(Elements.Performance()),
    BottomPanelConfig: panel => panel
        .Left(Elements.StartMenu())
        .Center(Elements.TaskBar())
        .Right(Elements.Clock().WithFormat("HH:mm:ss"))
);

// Or standalone
var panel = Panel.Builder()
    .Left(Elements.StatusText("Left"))
    .Center(Elements.TaskBar())
    .Right(Elements.Clock())
    .WithBackgroundColor(Color.DarkBlue)
    .Build();

Methods:

  • .Left(element) / .Center(element) / .Right(element) — Add element to zone
  • .WithBackgroundColor(Color) — Set background color
  • .WithForegroundColor(Color) — Set foreground color
  • .Visible(bool) — Set initial visibility
  • .Build() — Build the Panel

Elements Factory

The Elements static class returns element builders:

Elements.StatusText("text")    // StatusTextElementBuilder
Elements.Separator()           // SeparatorElementBuilder
Elements.TaskBar()             // TaskBarElementBuilder
Elements.Clock()               // ClockElementBuilder
Elements.Performance()         // PerformanceElementBuilder
Elements.StartMenu()           // StartMenuElementBuilder
Elements.Custom("name")        // CustomElementBuilder

Element Builder Examples

// StatusText with click handler
Elements.StatusText("[bold]Title[/]")
    .WithName("title")
    .WithColor(Color.Cyan1)
    .OnClick(() => ShowAbout())

// Clock with custom format
Elements.Clock()
    .WithFormat("HH:mm:ss")
    .WithColor(Color.Yellow)
    .WithUpdateInterval(1000)

// Start Menu with options
Elements.StartMenu()
    .WithText("☰ Start")
    .WithColors(Color.White, Color.DarkBlue)
    .WithShortcutKey(ConsoleKey.Spacebar, ConsoleModifiers.Control)
    .WithOptions(new StartMenuOptions { AppName = "My App" })

// TaskBar with colors
Elements.TaskBar()
    .WithActiveColor(Color.Cyan1)
    .WithInactiveColor(Color.Grey50)

// Custom element
Elements.Custom("indicator")
    .WithFixedWidth(12)
    .WithRenderCallback((buffer, x, y, width, fg, bg) =>
    {
        buffer.WriteString(x, y, "● Online", fg, bg);
    })

Control Builders

Control builders provide fluent APIs for configuring controls before adding them to windows.

ButtonBuilder

Controls.Button("Click Me")
    .WithWidth(20)
    .WithAlignment(HorizontalAlignment.Center)
    .WithMargin(0, 1, 0, 0)
    .WithName("submitButton")
    .OnClick((sender, e, window) =>
    {
        // Button click handler - window parameter available
    })
    .Build();

ListBuilder

Controls.List()
    .AddItem("Item 1")
    .AddItem("Item 2")
    .AddItem("Item 3")
    .WithHeight(10)
    .WithColors(Color.White, Color.Grey15)
    .OnItemActivated((sender, item, window) =>
    {
        // Item double-clicked or Enter pressed
    })
    .OnSelectionChanged((sender, index, window) =>
    {
        // Selection changed
    })
    .Build();

CheckboxBuilder

Controls.Checkbox("Enable feature", initialChecked: false)
    .OnCheckedChanged((sender, isChecked, window) =>
    {
        // Checkbox state changed
    })
    .Build();
Controls.Dropdown()
    .AddItem("Option 1")
    .AddItem("Option 2")
    .AddItem("Option 3")
    .WithWidth(30)
    .OnSelectionChanged((sender, index, window) =>
    {
        // Selection changed
    })
    .Build();

PromptBuilder

Controls.Prompt("Enter name:")
    .WithInitialText("")
    .WithMaxLength(50)
    .WithName("nameInput")
    .OnEntered((sender, text, window) =>
    {
        // Enter key pressed
    })
    .OnInputChanged((sender, text, window) =>
    {
        // Text changed
    })
    .Build();

MarkupBuilder

Controls.Markup()
    .AddLine("[bold yellow]Title[/]")
    .AddLine("")
    .AddLine("Regular text")
    .AddLine("[green]Success message[/]")
    .WithAlignment(HorizontalAlignment.Center)
    .Build();

Markdown

MarkupControl can render Markdown via the [markdown] tag. The builder exposes fluent helpers so you don't have to wrap the tag by hand:

// Controls.Markdown(...) seeds a MarkupBuilder with a Markdown block
Controls.Markdown("# Report\n\n**Status:** OK\n\n- item one\n- item two")
    .Build();

// Or append Markdown to an existing MarkupBuilder
Controls.Markup()
    .AddLine("[bold]Release notes[/]")
    .AddMarkdown("## Changes\n\n- Fixed a bug\n- Added a feature")   // WithMarkdown(...) is an alias
    .Build();

// Per-build style override (colorless emphasis/headings; only chrome is colored)
Controls.Markdown("# Heading\n\n> A quote with `code`")
    .WithMarkdownStyle(s => s with { LinkColor = Color.HotPink })
    .Build();
Helper Description
Controls.Markdown(text) Returns a MarkupBuilder seeded with a Markdown block
.AddMarkdown(text) Appends a Markdown block to the builder
.WithMarkdown(text) Alias for AddMarkdown
.WithMarkdownStyle(s => s with { … }) Per-build MarkdownStyle override

See Markup Syntax → Markdown for the supported constructs and the full MarkdownStyle reference.

TreeControlBuilder

Controls.Tree()
    .AddNode("Root", children =>
    {
        children.AddNode("Child 1");
        children.AddNode("Child 2", grandchildren =>
        {
            grandchildren.AddNode("Grandchild");
        });
    })
    .WithHeight(15)
    .WithColors(Color.Grey15, Color.White)
    .Build();

HorizontalGridBuilder

Controls.HorizontalGrid()
    .WithAlignment(HorizontalAlignment.Stretch)
    .Column(col => col.Add(Controls.Label("Left")))
    .Column(col => col.Add(Controls.Label("Middle")))
    .Column(col => col.Add(Controls.Label("Right")))
    .Build();

ScrollablePanelBuilder

Controls.ScrollablePanel()
    .AddControl(Controls.Label("Line 1"))
    .AddControl(Controls.Label("Line 2"))
    .AddControl(Controls.Label("Line 3"))
    .WithHeight(5)
    .Build();

CollapsiblePanelBuilder

Controls.CollapsiblePanel("Reasoning steps")
    .Collapsed()
    .WithHeaderStyle(CollapsibleHeaderStyle.Borderless)
    .WithIcons("▾", "▸")
    .WithHeaderSeparator()
    .WithMaxContentHeight(8)
    .AddControl(Controls.Markup()
        .AddLine("[dim]1. Parsed the request[/]")
        .AddLine("[dim]2. Queried the index[/]")
        .Build())
    .OnExpandedChanged((sender, expanded) => { /* react to toggle */ })
    .Build();

A click-to-expand container whose body hosts any IWindowControl (it implements IControlHost). See CollapsiblePanel for the full reference.

It can also act as a plain panel — set .NonCollapsible() (and optionally .HideHeader()) to lock it expanded with no toggle affordance. In panel mode the header is not a Tab stop; focus passes straight through to the body children:

// Panel mode: a bordered, headerless container that never collapses
Controls.CollapsiblePanel()
    .NonCollapsible()
    .HideHeader()
    .WithHeaderStyle(CollapsibleHeaderStyle.Bordered)
    .AddControl(Controls.Markup("[bold]Status[/]").Build())
    .AddControl(Controls.Button("Refresh").OnClick((_, _, _) => { }).Build())
    .Build();

A collapsible panel always shows its header (it is the only toggle affordance), so Collapsible=true, ShowHeader=false resolves to "header shown" — no exception is thrown.

Key Methods:

  • Controls.CollapsiblePanel(title?) - Create the builder, optionally seeding the title
  • .Collapsed() / .Expanded() - Initial expanded state
  • .WithHeaderStyle(CollapsibleHeaderStyle) - Borderless or Bordered
  • .WithIcons(expanded, collapsed) / .WithExpandedIcon() / .WithCollapsedIcon() - Indicator icons
  • .WithHeaderSeparator(bool) - Separator under a borderless header
  • .Collapsible(bool) / .NonCollapsible() - Lock the panel expanded as a plain panel (no toggle, pass-through focus)
  • .ShowHeader(bool) / .HideHeader() - Show or suppress the header row
  • .WithMaxContentHeight(int) - Cap the body height (wrap a ScrollablePanel to scroll)
  • .WithAnimation(mode) / .Animated() - Height tween on toggle
  • .WithHeaderAlignment(), .WithWidth(), .WithBorderColor(), .WithBackgroundColor(), .WithForegroundColor()
  • .AddControl(IWindowControl) - Add a body child
  • .OnExpandedChanged(EventHandler<bool>) - Expand/collapse event
Controls.Menu()
    .AddItem(item => item
        .WithText("File")
        .AddSubmenu(submenu => submenu
            .AddItem(i => i.WithText("New"))
            .AddItem(i => i.WithText("Open"))
            .AddSeparator()
            .AddItem(i => i.WithText("Exit"))
        )
    )
    .AddItem(item => item.WithText("Edit"))
    .Build();

ToolbarBuilder

Controls.Toolbar()
    .AddButton("New", onClick: (s, e, w) => { })
    .AddButton("Open", onClick: (s, e, w) => { })
    .AddSeparator()
    .AddButton("Save", onClick: (s, e, w) => { })
    .Build();

MultilineEditControlBuilder

Controls.MultilineEdit()
    .WithViewportHeight(10)
    .WithWrapMode(WrapMode.Wrap)
    .WithInitialText("Initial content")
    .Build();

FigleControlBuilder

Controls.Figle("BIG TEXT")
    .WithFont(FigletFont.Load("standard"))
    .WithAlignment(HorizontalAlignment.Center)
    .WithColor(Color.Yellow)
    .Build();
Controls.NavigationView()
    .WithNavWidth(26)
    .WithPaneHeader("[bold white]  ⚙  Settings[/]")
    .WithContentBorder(BorderStyle.Rounded)
    .WithContentBorderColor(Color.Grey37)
    .WithContentBackground(new Color(30, 30, 40))
    .WithContentPadding(1, 0, 1, 0)
    .AddItem("Home", subtitle: "Welcome page", content: panel =>
    {
        panel.AddControl(Controls.Label("Welcome!"));
    })
    .AddItem("Settings", subtitle: "App settings", content: panel =>
    {
        panel.AddControl(Controls.Checkbox("Notifications").Checked(true).Build());
    })
    .WithSelectedColors(Color.White, new Color(40, 50, 80))
    .WithAlignment(HorizontalAlignment.Stretch)
    .Fill()
    .OnSelectedItemChanged((sender, e) =>
    {
        // Handle selection change
    })
    .Build();

Key Methods:

  • AddItem(text, icon?, subtitle?, content?) - Add nav item with optional content factory
  • WithNavWidth(int) - Set nav pane width (default: 26, minimum: 10)
  • WithPaneHeader(string) - Set pane header markup
  • WithContentBorder(BorderStyle) - Set content panel border style
  • WithContentBackground(Color) - Set content panel background
  • WithContentHeader(bool) - Show/hide the title + subtitle header
  • WithSelectedIndex(int) - Set initially selected item
  • WithPaneDisplayMode(mode) - Set responsive mode (Auto, Expanded, Compact, Minimal)
  • WithExpandedThreshold(int) / WithCompactThreshold(int) - Set width thresholds
  • WithCompactPaneWidth(int) - Set compact mode nav width (default: 5)
  • WithAnimateTransitions(bool) - Enable/disable animated transitions
  • OnSelectedItemChanged(handler) / OnSelectedItemChanging(handler) - Events

SparklineBuilder

// Basic sparkline with block characters (default)
new SparklineBuilder()
    .WithHeight(6)
    .WithMaxValue(100)
    .WithBarColor(Color.Cyan1)
    .WithBorder(BorderStyle.Rounded, Color.Grey50)
    .WithTitle("CPU Usage %", Color.Cyan1)
    .WithData(cpuHistory)
    .Build();

// Braille mode for smoother appearance
new SparklineBuilder()
    .WithHeight(6)
    .WithMode(SparklineMode.Braille)  // Use braille patterns (5 levels)
    .WithMaxValue(100)
    .WithBarColor(Color.Green)
    .WithTitle("Memory %")
    .Build();

// Bidirectional mode for network upload/download visualization
new SparklineBuilder()
    .WithHeight(10)
    .WithMode(SparklineMode.BidirectionalBraille)  // Upload up, download down
    .WithMaxValue(100)                    // Primary (upload) max
    .WithSecondaryMaxValue(100)           // Secondary (download) max
    .WithBarColor(Color.Cyan1)            // Upload color (goes up from center)
    .WithSecondaryBarColor(Color.Green)   // Download color (goes down from center)
    .WithTitle("↑ Upload  ↓ Download", Color.Grey70)
    .WithBidirectionalData(uploadHistory, downloadHistory)
    .Build();

SparklineMode Options:

  • Block (default) - Uses 9-level block characters (▁▂▃▄▅▆▇█)
  • Braille - Uses 5-level braille patterns for smoother, denser appearance
  • Bidirectional - Two series: primary goes up from center, secondary goes down (block chars)
  • BidirectionalBraille - Same as Bidirectional but with braille patterns

Bidirectional Mode Methods:

  • WithSecondaryData(IEnumerable<double>) - Set secondary data series
  • WithSecondaryBarColor(Color) - Color for secondary (downward) bars
  • WithSecondaryMaxValue(double) - Max scale for secondary series
  • WithBidirectionalData(primary, secondary) - Set both series at once

BarGraphBuilder

// Basic bar graph with fixed color
new BarGraphBuilder()
    .WithLabel("CPU")
    .WithValue(65.5)
    .WithMaxValue(100)
    .WithBarWidth(30)
    .WithFilledColor(Color.Cyan1)
    .WithUnfilledColor(Color.Grey35)
    .ShowLabel()
    .ShowValue()
    .WithValueFormat("F1")
    .Build();

// Bar graph with gradient thresholds
new BarGraphBuilder()
    .WithLabel("RAM Used")
    .WithValue(75.0)
    .WithMaxValue(100)
    .WithBarWidth(30)
    .WithStandardGradient()  // Green (0-49%), Yellow (50-79%), Red (80%+)
    .Build();

// Custom gradient thresholds
new BarGraphBuilder()
    .WithLabel("Swap")
    .WithValue(30.0)
    .WithMaxValue(100)
    .WithGradient(
        new ColorThreshold(0, Color.Green),
        new ColorThreshold(25, Color.Yellow),
        new ColorThreshold(50, Color.Red)
    )
    .Build();

// Aligned bar graphs with fixed label width
new BarGraphBuilder()
    .WithLabel("RAM Used")
    .WithLabelWidth(12)  // All bars align at position 12 + ": "
    .WithValue(75.0)
    .WithMaxValue(100)
    .WithBarWidth(30)
    .Build();

Key Methods:

  • WithLabelWidth(int) - Fixed label column width for vertical alignment
  • WithGradient(params ColorThreshold[]) - Set custom color thresholds
  • WithStandardGradient() - Convenience method for green/yellow/red at 0/50/80%

TerminalBuilder

Platform: Linux only. Requires PtyShim.RunIfShim(args) at the start of Main — see TerminalControl.

// Quick open — auto-sized window
Controls.Terminal().Open(ws);

// Explicit size (cols × rows)
Controls.Terminal().Open(ws, width: 120, height: 40);

// Different executable
Controls.Terminal("/usr/bin/htop").Open(ws);

// With arguments, manual window
var terminal = Controls.Terminal("/usr/bin/vim")
    .WithArgs("/etc/hosts")
    .Build();

var window = new WindowBuilder(ws)
    .WithTitle(terminal.Title)
    .WithSize(102, 42)
    .Centered()
    .Closable(true)
    .AddControl(terminal)
    .Build();

ws.AddWindow(window);

Methods:

  • WithExe(string) — Executable to launch (default: /bin/bash)
  • WithArgs(params string[]) — Arguments passed to the executable
  • Build() — Opens the PTY and returns a TerminalControl
  • Open(ws, width?, height?) — Build and open in a new centered window

SpectreRenderableBuilder

var table = new Table()
    .AddColumn("Name")
    .AddColumn("Value")
    .AddRow("Item 1", "100")
    .AddRow("Item 2", "200");

Controls.SpectreRenderable(table)
    .WithAlignment(HorizontalAlignment.Center)
    .Build();

RuleBuilder

Controls.RuleBuilder()
    .WithTitle("Section Title")
    .WithColor(Color.Blue)
    .StickyTop()  // Stick to top of window
    .Build();

PanelBuilder

// Basic panel with content
Controls.Panel()
    .WithContent("[yellow bold]Panel Title[/]")
    .WithHeader("Header Text")
    .Rounded()  // Use rounded border
    .WithBorderColor(Color.Cyan1)
    .WithPadding(2, 1)
    .Build();

// Different border styles
Controls.Panel()
    .WithContent("Double line border")
    .DoubleLine()
    .Build();

Controls.Panel()
    .WithContent("Single line border")
    .SingleLine()
    .Build();

Controls.Panel()
    .WithContent("No border")
    .NoBorder()
    .Build();

// Panel that fills available height
Controls.Panel()
    .WithContent("Stretches vertically")
    .FillVertical()
    .Build();

// With header alignment
Controls.Panel()
    .WithContent("Content here")
    .WithHeader("Centered Header")
    .HeaderCenter()
    .Build();

Border Styles:

  • Rounded() - Rounded corners (╭─╮│╰╯)
  • DoubleLine() - Double-line border (╔═╗║╚╝)
  • SingleLine() - Single-line border (┌─┐│└┘)
  • NoBorder() - No visible border

Key Methods:

  • WithContent(string) - Set text content (supports markup syntax)
  • WithContent(IRenderable) - Set any Spectre renderable as content
  • WithHeader(string) - Add header text to border
  • HeaderLeft() / HeaderCenter() / HeaderRight() - Header alignment
  • WithPadding(int) or WithPadding(left, top, right, bottom) - Inner padding
  • WithBorderColor(Color) - Border color
  • FillVertical() - Stretch panel to fill available height
  • WithHeight(int) - Set explicit height

Controls Static Factory

The Controls static class provides convenient factory methods.

Quick Creation Methods

// Simple controls (no builder needed)
Controls.Label("Text")              // Plain text label
Controls.Header("Title")            // Bold yellow header
Controls.Info("Info message")       // Blue info text
Controls.Warning("Warning")         // Orange warning text
Controls.Error("Error message")     // Red error text
Controls.Success("Success!")        // Green success text
Controls.Rule("Section")            // Horizontal rule with title
Controls.Separator()                // Plain horizontal line
Controls.Space()                    // Empty space/padding

Builder Methods

// Returns builders for fluent configuration
Controls.Button(text)               // ButtonBuilder
Controls.Markup(line)               // MarkupBuilder
Controls.Markdown(markdown)         // MarkupBuilder seeded with a [markdown] block
Controls.List()                     // ListBuilder
Controls.Checkbox(label, checked)   // CheckboxBuilder
Controls.Dropdown()                 // DropdownBuilder
Controls.Prompt(prompt)             // PromptBuilder
Controls.Tree()                     // TreeControlBuilder
Controls.HorizontalGrid()           // HorizontalGridBuilder
Controls.ScrollablePanel()          // ScrollablePanelBuilder
Controls.CollapsiblePanel(title?)   // CollapsiblePanelBuilder (click-to-expand container)
Controls.Menu()                     // MenuBuilder
Controls.Toolbar()                  // ToolbarBuilder
Controls.MultilineEdit()            // MultilineEditControlBuilder
Controls.Figle(text)                // FigleControlBuilder
Controls.SpectreRenderable(widget)  // SpectreRenderableBuilder
Controls.RuleBuilder()              // RuleBuilder
Controls.Panel()                    // PanelBuilder (for bordered content panels)
Controls.Panel(text)                // PanelControl directly with text content
Controls.NavigationView()           // NavigationViewBuilder (sidebar nav + content area)
Controls.Terminal(exe?)             // TerminalBuilder — Linux only, requires PtyShim setup
new SparklineBuilder()              // SparklineBuilder (for time-series graphs)
new BarGraphBuilder()               // BarGraphBuilder (for horizontal bar graphs)

Builder Patterns

Common Pattern: Name and Find

Name controls to find them later:

window.AddControl(
    Controls.Prompt("Enter name:")
        .WithName("nameInput")
        .Build()
);

window.AddControl(
    Controls.Label("Status: Ready")
        .WithName("statusLabel")
        .Build()
);

// Later, find by name
var nameInput = window.FindControl<PromptControl>("nameInput");
var statusLabel = window.FindControl<MarkupControl>("statusLabel");

Common Pattern: Event Handlers with Window Access

All event handlers include a window parameter:

window.AddControl(
    Controls.Button("Submit")
        .OnClick((sender, e, window) =>
        {
            // Access other controls through window parameter
            var input = window.FindControl<PromptControl>("nameInput");
            var status = window.FindControl<MarkupControl>("status");

            if (!string.IsNullOrWhiteSpace(input?.Text))
            {
                status?.SetContent($"[green]Hello, {input.Text}![/]");
            }
        })
        .Build()
);

Common Pattern: Layout with Alignment

window.AddControl(
    Controls.Header("Welcome")
        .WithAlignment(HorizontalAlignment.Center)
        .Build()
);

window.AddControl(
    Controls.Button("Submit")
        .WithWidth(20)
        .WithAlignment(HorizontalAlignment.Center)
        .Build()
);

Common Pattern: Sticky Positioning

// Stick to top
window.AddControl(
    Controls.RuleBuilder()
        .WithTitle("Header")
        .StickyTop()
        .Build()
);

// Stick to bottom
window.AddControl(
    Controls.Label("Press ESC to close")
        .WithAlignment(HorizontalAlignment.Right)
        .StickyBottom()
        .Build()
);

Common Pattern: Margins

window.AddControl(
    Controls.Label("Text with margins")
        .WithMargin(left: 2, top: 1, right: 2, bottom: 1)
        .Build()
);

Complete Application Example

using SharpConsoleUI;
using SharpConsoleUI.Builders;
using SharpConsoleUI.Drivers;

var windowSystem = new ConsoleWindowSystem(new NetConsoleDriver(RenderMode.Buffer));

var mainWindow = new WindowBuilder(windowSystem)
    .WithTitle("Contact Form")
    .WithSize(60, 20)
    .Centered()
    .WithColors(Color.White, Color.DarkBlue)
    .Build();

// Header
mainWindow.AddControl(
    Controls.Header("Contact Information")
        .WithAlignment(HorizontalAlignment.Center)
        .Build()
);

mainWindow.AddControl(Controls.Space());

// Name input
mainWindow.AddControl(
    Controls.Prompt("Name:")
        .WithName("nameInput")
        .WithMaxLength(50)
        .OnInputChanged((sender, text, window) =>
        {
            var status = window.FindControl<MarkupControl>("statusLabel");
            status?.SetContent($"[dim]Typing... ({text.Length} chars)[/]");
        })
        .Build()
);

// Email input
mainWindow.AddControl(
    Controls.Prompt("Email:")
        .WithName("emailInput")
        .WithMaxLength(100)
        .Build()
);

mainWindow.AddControl(Controls.Space());

// Message input
mainWindow.AddControl(Controls.Label("Message:"));
mainWindow.AddControl(
    Controls.MultilineEdit()
        .WithName("messageInput")
        .WithViewportHeight(5)
        .WithWrapMode(WrapMode.Wrap)
        .Build()
);

mainWindow.AddControl(Controls.Space());

// Buttons
mainWindow.AddControl(
    Controls.HorizontalGrid()
        .Column(col => col.Add(
            Controls.Button("Submit")
                .OnClick((sender, e, window) =>
                {
                    var name = window.FindControl<PromptControl>("nameInput");
                    var email = window.FindControl<PromptControl>("emailInput");
                    var message = window.FindControl<MultilineEditControl>("messageInput");

                    if (string.IsNullOrWhiteSpace(name?.Text))
                    {
                        windowSystem.NotificationStateService.ShowNotification(
                            "Validation Error",
                            "Name is required",
                            NotificationSeverity.Warning
                        );
                        return;
                    }

                    // Process form...
                    windowSystem.NotificationStateService.ShowNotification(
                        "Success",
                        "Message sent successfully!",
                        NotificationSeverity.Success
                    );
                })
                .Build()
        ))
        .Column(col => col.Add(
            Controls.Button("Clear")
                .OnClick((sender, e, window) =>
                {
                    window.FindControl<PromptControl>("nameInput")?.Clear();
                    window.FindControl<PromptControl>("emailInput")?.Clear();
                    window.FindControl<MultilineEditControl>("messageInput")?.Clear();
                })
                .Build()
        ))
        .Build()
);

// Status label
mainWindow.AddControl(
    Controls.Label("Ready")
        .WithName("statusLabel")
        .WithAlignment(HorizontalAlignment.Center)
        .StickyBottom()
        .Build()
);

windowSystem.AddWindow(mainWindow);
windowSystem.Run();

Back to Main Documentation