SquidStd.Tui
0.28.0
dotnet add package SquidStd.Tui --version 0.28.0
NuGet\Install-Package SquidStd.Tui -Version 0.28.0
<PackageReference Include="SquidStd.Tui" Version="0.28.0" />
<PackageVersion Include="SquidStd.Tui" Version="0.28.0" />
<PackageReference Include="SquidStd.Tui" />
paket add SquidStd.Tui --version 0.28.0
#r "nuget: SquidStd.Tui, 0.28.0"
#:package SquidStd.Tui@0.28.0
#addin nuget:?package=SquidStd.Tui&version=0.28.0
#tool nuget:?package=SquidStd.Tui&version=0.28.0
<h1 align="center">SquidStd.Tui</h1>
MVVM for terminal apps, built on Terminal.Gui v2 and CommunityToolkit.Mvvm. Observable ViewModels, a View↔ViewModel binder (fluent + opt-in convention), ViewModel-first navigation, and DryIoc wiring.
Install
dotnet add package SquidStd.Tui
Usage
public sealed partial class CounterViewModel : TuiViewModel
{
[ObservableProperty] private string _title = "Counter";
[ObservableProperty] private string _value = "0";
[RelayCommand]
private void Increment() => Value = (int.Parse(Value) + 1).ToString();
}
public sealed class CounterView : TuiView<CounterViewModel>
{
private Label _value = null!;
private Button _inc = null!;
protected override void BuildLayout()
{
_value = new Label { X = 1, Y = 1 };
_inc = new Button { X = 1, Y = 3, Text = "+1" };
Add(_value, _inc);
}
protected override void Bind(ViewBinder b)
{
b.OneWayTitle(ViewModel, x => x.Title, this);
b.OneWayText(ViewModel, x => x.Value, _value);
b.Command(_inc, ViewModel.IncrementCommand);
}
}
// boot
var container = new Container().RegisterTui();
container.RegisterView<CounterView, CounterViewModel>();
await container.Resolve<TuiApplicationHost>().RunAsync<CounterViewModel>();
Declarative UI (DSL)
Instead of imperative BuildLayout + Bind, derive from TuiComposedView<TViewModel> and return a node
tree from Compose(). One node = widget + binding; direction is inferred (Label one-way, TextField
two-way, Button command) and bindings are typed lambdas - no magic strings.
public sealed class CounterView : TuiComposedView<CounterViewModel>
{
protected override TuiNode<CounterViewModel> Compose() =>
Ui.VStack(
Ui.Label(x => x.Title),
Ui.Label(x => x.Value),
Ui.Button("+1", x => x.IncrementCommand));
}
Ui.VStack/Ui.HStack arrange children automatically; Ui.TextField(x => x.Name) is two-way by default
(pass BindMode.OneWay to override).
Key types
| Type | Purpose |
|---|---|
TuiViewModel |
ViewModel base (ObservableObject + activation hooks + Navigator). |
TuiView<TViewModel> |
View base: a Terminal.Gui Window with a typed ViewModel and a binder. |
ViewBinder |
One-way / two-way / command binding; fluent typed + AutoBind by convention. |
ITuiNavigator |
ViewModel-first stack navigation (NavigateToAsync, BackAsync). |
TuiApplicationHost |
Boots the Terminal.Gui loop with a root ViewModel. |
RegisterTui() / RegisterView<,>() |
DryIoc registration. |
Related
- Article: Terminal UI
- Tutorial: Terminal UI (MVVM)
License
MIT - part of SquidStd.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- CommunityToolkit.Mvvm (>= 8.4.2)
- DryIoc.dll (>= 5.4.3)
- Terminal.Gui (>= 2.4.16)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.28.0 | 47 | 7/8/2026 |
| 0.27.0 | 47 | 7/7/2026 |
| 0.26.0 | 36 | 7/7/2026 |
| 0.25.0 | 94 | 7/6/2026 |
| 0.24.1 | 93 | 7/6/2026 |
| 0.24.0 | 91 | 7/6/2026 |
| 0.23.0 | 90 | 7/4/2026 |
| 0.22.0 | 89 | 7/4/2026 |
| 0.21.0 | 90 | 7/3/2026 |
| 0.20.0 | 84 | 7/3/2026 |
| 0.19.0 | 91 | 7/3/2026 |
| 0.18.0 | 92 | 7/3/2026 |
| 0.17.0 | 98 | 7/3/2026 |
| 0.16.0 | 94 | 7/3/2026 |
| 0.15.0 | 96 | 7/2/2026 |
| 0.14.1 | 90 | 7/2/2026 |
| 0.14.0 | 87 | 7/2/2026 |
| 0.13.0 | 87 | 7/2/2026 |
| 0.12.0 | 92 | 7/2/2026 |
| 0.11.0 | 90 | 7/2/2026 |