docfx/docs/View.md
View is the base class for all visible UI elements in Terminal.Gui. View provides core functionality for layout, drawing, input handling, navigation, and scrolling. All interactive controls, windows, and dialogs derive from View.
See the Views Overview for a catalog of all built-in View subclasses.
Add()SuperView property that references its containerSubViews - Read-only list of all SubViews added to this ViewSuperView - The xref:Terminal.Gui.ViewBase.View's container (null if the View has no container)Id - Unique identifier for the View (should be unique among siblings)Data - Arbitrary data attached to the ViewApp - The application context this View belongs toDriver - The driver used for rendering (derived from App). This is a shortcut to App.Driver for convenience.Views are composed of several nested layers that define how they are positioned, drawn, and scrolled:
[!INCLUDE View Composition]
Frame - The outermost rectangle defining the View's location and size relative to the SuperView's content areaViewport - Rectangle describing the visible portion of the content areaGetContentSize())See the Layout Deep Dive for complete details on View composition and layout.
// Frame is SuperView-relative
view.Frame = new Rectangle (10, 5, 50, 20);
// Viewport is content-relative (the visible portal)
view.Viewport = new Rectangle (0, 0, 45, 15); // Adjusted for adornments
The Content Area is where the View's content is drawn. By default, the content area size matches the Viewport size. To enable scrolling:
SetContentSize() with a size larger than the ViewportViewport.Location to scroll the contentSee the Scrolling Deep Dive for complete details.
Adornments are lightweight objects that define the spacing around a View's content. When View-level features are needed (e.g., SubViews, shadows), a full AdornmentView is lazily created via GetOrCreateView():
See the Layout Deep Dive for complete details on adornments.
Views implement ISupportInitializeNotification:
BeginInit() - Signals initialization is startingEndInit() - Signals initialization is complete; raises Initialized eventIsInitialized - Property indicating if initialization is completeDuring initialization, App is set to reference the application context, enabling views to access application services like the driver and current session.
Views are IDisposable:
Dispose() to clean up resourcesDisposing event is raised when disposal beginsView is organized as a partial class across multiple files, each handling a specific subsystem:
See the Command Deep Dive.
CommandsToBubbleUp - Opt-in list of commands that bubble from SubViews to this ViewTryBubbleToSuperView)DefaultAcceptView - The SubView that receives xref:Terminal.Gui.Input.Command.Accept when no other SubView handles itSee the Keyboard Deep Dive.
HotKeySpecifier - Character used to denote hot keys in text (default: '_')KeyDown, InvokingKeyBindingsSee the Mouse Deep Dive.
MouseHoldRepeat - Enables continuous button press eventsMouseEnter, MouseLeave, MouseEventSee the Layout Deep Dive and Arrangement Deep Dive.
X - Horizontal position using PosY - Vertical position using PosWidth - Width using DimHeight - Height using DimDim.Auto() - Automatic sizing based on contentPos.AnchorEnd() - Anchor to right/bottom edgesArrangement - Controls if View is movable/resizableLayoutStarted - Before layout beginsLayoutComplete - After layout completesFrameChanged - When Frame changesViewportChanged - When Viewport changesSee the Drawing Deep Dive.
See the Scheme Deep Dive for details on color theming.
[!WARNING]
Move()sets the Draw Cursor (where next character renders), NOT the Terminal Cursor (visible cursor indicator). To position the Terminal Cursor, use theView.Cursorproperty. See Cursor Management for details.
DrawingContent - Before content is drawnDrawingContentComplete - After content is drawnDrawingAdornments - Before adornments are drawnDrawingAdornmentsComplete - After adornments are drawnSee the Navigation Deep Dive.
Events:
HasFocusChanging - Before focus changes (cancellable)HasFocusChanged - After focus changesSee the Scrolling Deep Dive.
Viewport - Visible portion of the content areaGetContentSize() - Returns size of scrollable contentSetContentSize() - Sets size of scrollable contentScrollHorizontal() - Scrolls content horizontallyScrollVertical() - Scrolls content verticallyVerticalScrollBar - Built-in vertical scrollbarHorizontalScrollBar - Built-in horizontal scrollbarViewportSettings - ViewportSettingsFlags controlling scroll behaviorText - The View's text contentTitle - The View's title (shown in Border)TextFormatter - Handles text formatting and alignmentTextDirection - Text direction (LeftRight, RightToLeft, TopToBottom)TextAlignment - Text alignment (Left, Centered, Right, Justified)VerticalTextAlignment - Vertical alignment (Top, Middle, Bottom, Justified)View view = new ()
{
X = Pos.Center (),
Y = Pos.Center (),
Width = Dim.Percent (50),
Height = Dim.Fill ()
};
When a xref:Terminal.Gui.ViewBase.View is added to a SuperView or when Application.Run is called:
BeginInit() is calledEndInit() is calledIsInitialized becomes trueLayout happens automatically when needed:
LayoutStarted event is raisedLayoutComplete event is raisedDrawing happens automatically when needed:
DrawingContent event is raisedDrawingContentComplete event is raisedInput is processed in this order:
view.Dispose ();
See the Command Deep Dive for complete details.
Views use a command pattern for handling input:
// Add a command the view supports
view.AddCommand (Command.Accept, () =>
{
// Handle the Accept command
return true;
});
// Bind a key to the command
view.KeyBindings.Add (Key.Enter, Command.Accept);
// Bind a mouse action to the command
view.MouseBindings.Add (MouseFlags.LeftButtonClicked, Command.Activate);
// Enable command bubbling from SubViews to this View
view.CommandsToBubbleUp = [Command.Accept, Command.Activate];
// Set the default view that receives Accept when no other SubView handles it
// (typically a Button with IsDefault = true, found automatically via IAcceptTarget)
view.DefaultAcceptView = okButton;
See the Keyboard Deep Dive for complete details.
The keyboard subsystem processes key presses through:
See the Mouse Deep Dive for complete details.
The mouse subsystem processes mouse events through:
See the Layout Deep Dive for complete details.
Layout is declarative using Pos and Dim:
Label label = new () { Text = "Name:" };
TextField textField = new ()
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = Dim.Fill ()
};
The layout system automatically:
See the Drawing Deep Dive for complete details.
Views draw themselves using viewport-relative coordinates:
protected override bool OnDrawingContent ()
{
// Draw at viewport coordinates (0,0)
Move (0, 0);
SetAttribute (new Attribute (Color.White, Color.Blue));
AddStr ("Hello, Terminal.Gui!");
return true;
}
Key drawing concepts:
See the Navigation Deep Dive for complete details.
Navigation controls keyboard focus movement:
See the Scrolling Deep Dive for complete details.
Scrolling is built into every View:
// Set content size larger than viewport
view.SetContentSize(new Size(100, 100));
// Scroll the content
view.Viewport = view.Viewport with { Location = new Point(10, 10) };
// Or use helper methods
view.ScrollVertical(5);
view.ScrollHorizontal(3);
// Enable scrollbars
view.ViewportSettings |= ViewportSettingsFlags.HasVerticalScrollBar;
view.ViewportSettings |= ViewportSettingsFlags.HasHorizontalScrollBar;
public class MyCustomView : View
{
public MyCustomView ()
{
// Set up default size
Width = Dim.Auto ();
Height = Dim.Auto ();
// Can receive focus
CanFocus = true;
// Add supported commands
AddCommand (Command.Accept, HandleAccept);
// Configure key bindings
KeyBindings.Add (Key.Enter, Command.Accept);
}
protected override bool OnDrawingContent ()
{
// Draw custom content using viewport coordinates
Move (0, 0);
SetAttributeForRole (VisualRole.Normal);
AddStr ("My custom content");
return true; // Handled
}
private bool HandleAccept ()
{
// Handle the Accept command
// Raise events, update state, etc.
return true; // Handled
}
}
View container = new ()
{
Width = Dim.Fill (),
Height = Dim.Fill ()
};
Button leftButton = new () { Text = "OK", X = 2, Y = 2 };
Button middleButton = new () { Text = "Cancel", X = Pos.Right (leftButton) + 2, Y = 2 };
container.Add (leftButton, middleButton);
View view = new ()
{
BorderStyle = LineStyle.Double,
Title = "My View"
};
// Configure border
view.Border.Thickness = new Thickness (1);
view.Border.Settings = BorderSettings.Title;
// Add padding
view.Padding.Thickness = new Thickness (1);
// Add margin
view.Margin.Thickness = new Thickness (2);
View view = new ()
{
Width = 40,
Height = 20
};
// Set content larger than viewport
view.SetContentSize (new Size (100, 100));
// Enable scrollbars with automatic visibility
view.ViewportSettings |= ViewportSettingsFlags.HasVerticalScrollBar;
view.ViewportSettings |= ViewportSettingsFlags.HasHorizontalScrollBar;
// Add key bindings for scrolling
view.KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
view.KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
view.KeyBindings.Add (Key.CursorLeft, Command.ScrollLeft);
view.KeyBindings.Add (Key.CursorRight, Command.ScrollRight);
// Add command handlers
view.AddCommand (Command.ScrollUp, () => { view.ScrollVertical (-1); return true; });
view.AddCommand (Command.ScrollDown, () => { view.ScrollVertical (1); return true; });
Views can implement IRunnable to run as independent, blocking sessions with typed results. This decouples runnability from inheritance, allowing any xref:Terminal.Gui.ViewBase.View to participate in session management.
The IRunnable pattern provides:
IRunnable<TResult> instead of inheriting from RunnableTResult parameter for compile-time type safetyInit(), Run(), and Shutdown() for concise codeIsRunningChanging/Changed, IsModalChanging/ChangedDerive from Runnable<TResult> or implement IRunnable<TResult>:
public class ColorPickerDialog : Runnable<Color?>
{
private ColorPicker16 _colorPicker;
public ColorPickerDialog ()
{
Title = "Select a Color";
_colorPicker = new ColorPicker16 { X = Pos.Center (), Y = 2 };
Button okButton = new () { Text = "OK", IsDefault = true };
okButton.Accepting += (_, e) =>
{
Result = _colorPicker.SelectedColor;
Application.RequestStop ();
};
Add (_colorPicker, okButton);
}
}
The fluent API enables elegant, concise code with automatic disposal:
// Framework creates, runs, and disposes the runnable automatically
Color? result = Application.Create ()
.Init ()
.Run<ColorPickerDialog> ()
.Shutdown () as Color?;
if (result is { })
{
Console.WriteLine($"Activated: {result}");
}
For more control over the lifecycle:
IApplication app = Application.Create ();
app.Init ();
ColorPickerDialog dialog = new ();
app.Run (dialog);
// Extract result after Run returns
Color? result = dialog.Result;
// Caller is responsible for disposal
dialog.Dispose ();
app.Shutdown ();
"Whoever creates it, owns it":
Run<TRunnable>(): Framework creates → Framework disposes (in Shutdown())Run(IRunnable): Caller creates → Caller disposesExtract the result in OnIsRunningChanging when stopping:
protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
{
if (!newIsRunning) // Stopping - extract result before disposal
{
Result = _colorPicker.SelectedColor;
// Optionally cancel stop (e.g., prompt to save)
if (HasUnsavedChanges ())
{
return true; // Cancel stop
}
}
return base.OnIsRunningChanging (oldIsRunning, newIsRunning);
}
IsRunning - True when on the RunnableSessionStackIsModal - True when at the top of the stack (receiving all input)Result - The typed result value (set before stopping)IsRunningChanging - Cancellable event before added/removed from stackIsRunningChanged - Non-cancellable event after stack changeIsModalChanged - Non-cancellable event after modal state changeViews can run modally (exclusively capturing all input until closed). See Runnable for the legacy pattern.
Note: New code should use IRunnable<TResult> pattern (see above) for better type safety and lifecycle management.
Dialog dialog = new ()
{
Title = "Confirmation",
Width = Dim.Percent (50),
Height = Dim.Percent (50)
};
// Add content...
Label label = new () { Text = "Are you sure?", X = Pos.Center (), Y = 1 };
dialog.Add (label);
// Run modally - blocks until closed
Application.Run (dialog);
// Dialog has been closed
dialog.Dispose ();
Wizards let users step through multiple pages:
Wizard wizard = new () { Title = "Setup Wizard" };
WizardStep step1 = new () { Title = "Welcome" };
step1.Add (new Label { Text = "Welcome to the wizard!", X = 1, Y = 1 });
WizardStep step2 = new () { Title = "Configuration" };
step2.Add (new TextField { X = 1, Y = 1, Width = 30 });
wizard.AddStep (step1);
wizard.AddStep (step2);
Application.Run (wizard);
View.Diagnostics - ViewDiagnosticFlags for debugging:
Ruler - Shows a ruler around the ViewDrawIndicator - Shows an animated indicator when drawingFramePadding - Highlights the Frame with colorEnabled - Whether the View is enabledVisible - Whether the View is visibleShadows are drop-shadow effects rendered by the xref:Terminal.Gui.ViewBase.Margin. They are configured via xref:Terminal.Gui.ViewBase.View.ShadowStyle:
ShadowStyle.None — No shadow (default).ShadowStyle.Opaque — Draws solid block glyphs (e.g., ▌, ▀) along the right and bottom edges. The foreground is black and the background matches whatever is underneath. Best for small views like buttons.ShadowStyle.Transparent — Preserves the underlying text but darkens the foreground and background colors. Best for larger views like windows and dialogs where obscuring content would be undesirable.view.ShadowStyle = ShadowStyle.Transparent;
When a shadow is enabled, the Margin's xref:Terminal.Gui.Drawing.Thickness is automatically increased on the right and bottom to make room for the shadow area. Two internal ShadowView instances (one vertical, one horizontal) are added as SubViews of the Margin.
Shadows are drawn in a second pass after all views have been drawn (via Margin.DrawShadows). This ensures shadows render on top of all other content. Margins without shadows are drawn normally in the first pass. See Drawing Deep Dive for details on the two-pass rendering process.
For interactive views, shadows also provide visual feedback on mouse press — the shadow shifts to create a "sunken" 3D button effect.