PromptPlus

PromptPlus # PromptPlus ## **MultiSelect<T> — Methods** [![NuGet](https://img.shields.io/badge/NuGet-PromptPlus-blue)](https://www.nuget.org/packages/PromptPlus) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![.NET](https://img.shields.io/badge/.NET-8%20%7C%209%20%7C%2010-512BD4)](https://dotnet.microsoft.com/)

← Back to HomeNext: MultiSelect — Operations →


Every fluent method on IMultiSelectControl<T>. Each returns the same control instance, so calls chain in any order. Call Run last.

The factory is PromptPlus.Controls.MultiSelect<T>(string prompt = "", string? description = null), which returns IMultiSelectControl<T>.

Quick jump: AddItem · AddItems · AddGroupedItem · AddGroupedItems · AddSeparator · Interaction · InteractionAsync · TextSelector · TextSelectorAsync · ExtraInfo · ExtraInfoAsync · HideTipGroup · Filter · PageSize · Default · UseDefaultHistory · DefaultMatchBy · Range · PredicateChecked · PredicateCheckedAsync · ViewOnly · ChangeDescription · ChangeDescriptionAsync · EnableHistory · Styles · Options · Run


Adding items

AddItem

IMultiSelectControl<T> AddItem(T value, bool ischecked = false, bool disable = false)

Adds a single item. Set ischecked: true to pre-check it; set disable: true to show it grayed out and non-selectable.

PromptPlus.Controls.MultiSelect<string>("Toppings")
    .AddItem("Cheese", ischecked: true)   // starts checked
    .AddItem("Onions")
    .AddItem("Anchovies", disable: true)  // visible but not selectable
    .Run();

Throws ArgumentNullException if value is null.


AddItems

IMultiSelectControl<T> AddItems(IEnumerable<T> values, bool ischecked = false, bool disable = false)

Adds many items at once. ischecked: true pre-checks all of them; disable: true disables all of them.

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(["Seattle", "London", "Tokyo"])
    .Run();

AddGroupedItem

IMultiSelectControl<T> AddGroupedItem(string group, T value, bool ischecked = false, bool disable = false)

Adds one item under a named group header. Pre-check it with ischecked: true.


AddGroupedItems

IMultiSelectControl<T> AddGroupedItems(string group, IEnumerable<T> values, bool ischecked = false, bool disable = false)

Adds many items under a named group header. Items keep their group as they scroll.

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddGroupedItems("North America", ["Seattle", "New York"])
    .AddGroupedItems("Asia",          ["Tokyo", "Singapore"])
    .Run();

A hint shows the group of the focused item; hide it with HideTipGroup. Pressing Space on a group header toggles every item in that group — see Operations.


AddSeparator

IMultiSelectControl<T> AddSeparator(SeparatorLine separatorLine = SeparatorLine.SingleLine, char? value = null)

Inserts a visual divider between items.

SeparatorLine Renders
SingleLine A single-line rule (default)
DoubleLine A double-line rule
UserChar A row of the character passed in value
PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItem("Seattle")
    .AddSeparator()                          // single line
    .AddItem("Tokyo")
    .AddSeparator(SeparatorLine.DoubleLine)  // double line
    .AddItem("London")
    .AddSeparator(SeparatorLine.UserChar, '*')
    .AddItem("Other")
    .Run();

Loading from a source

Interaction

IMultiSelectControl<T> Interaction<T1>(IEnumerable<T1> items, Action<T1, IMultiSelectControl<T>> interactionAction)

Iterates a source collection and lets you add items programmatically — useful when mapping from a different shape or applying per-item logic.

PromptPlus.Controls.MultiSelect<(int id, string City, string other)>("Cities")
    .Interaction(MyCities(), (row, ctrl) => ctrl.AddItem(row))
    .TextSelector(row => row.City)
    .Run();

InteractionAsync

IMultiSelectControl<T> InteractionAsync<T1>(IEnumerable<T1> items, Func<T1, IMultiSelectControl<T>, Task> interactionAction)

Asynchronous version of Interaction, for sources that need awaiting per item. The returned task is awaited synchronously (blocking).


Item text & info

TextSelector

IMultiSelectControl<T> TextSelector(Func<T, string> value)

Sets how each item is rendered as text. By default ToString() is used (and [Display] names for enums). Provide a selector for custom types.

PromptPlus.Controls.MultiSelect<User>("Users")
    .AddItems(users)
    .TextSelector(u => $"{u.Name} <{u.Email}>")
    .Run();

TextSelectorAsync

IMultiSelectControl<T> TextSelectorAsync(Func<T, Task<string>> value)

Asynchronous version of TextSelector.


ExtraInfo

IMultiSelectControl<T> ExtraInfo(Func<T, string?> extraInfoNode)

Shows a secondary piece of text for the focused item (return null to show nothing). It is wrapped with the prefix/suffix from config (default ( )). It also appears in the live answer line while navigating (not in the final checked-items summary shown after Enter) — see Operations.

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(["Seattle", "Tokyo"])
    .ExtraInfo(city => $"Length: {city.Length}")
    .Run();

ExtraInfoAsync

IMultiSelectControl<T> ExtraInfoAsync(Func<T, Task<string?>> extraInfoNode)

Asynchronous version of ExtraInfo. The task is awaited synchronously each time the cursor moves.


HideTipGroup

IMultiSelectControl<T> HideTipGroup(bool value = true)

Hides the “current group” hint shown for grouped lists. Default false (hint visible).


Filtering & paging

Filter

IMultiSelectControl<T> Filter(FilterMode value)

Controls live filtering as the user types.

FilterMode Behavior
Disabled No filtering (default)
Contains Match items containing the typed text
StartsWith Match items starting with the typed text
PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(cities)
    .Filter(FilterMode.StartsWith)
    .Run();

When filtering is Disabled, a printable key instead jumps to the next item starting with that character. See Operations.


PageSize

IMultiSelectControl<T> PageSize(byte value)

Rows visible at once (valid range 0–255). 0 (default) auto-computes from terminal height, reserving lines for the header, footer, and pagination. Values above the available height are clamped.

PromptPlus.Controls.MultiSelect<string>("Cities").AddItems(cities).PageSize(8).Run();

Initial value & equality

Default

IMultiSelectControl<T> Default(IEnumerable<T> values, bool useDefaultHistory = true)

Pre-checks every item that matches a value in values, and moves focus to the first match. When useDefaultHistory is true and history is enabled, the last history entry is preferred over values. Matching uses DefaultMatchBy if provided, otherwise default equality.

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(cities)
    .Default(["Tokyo", "Seattle"])
    .Run();

Note the difference from Select<T>.Default: this takes a collection of values, since multiple items can start checked.

Throws ArgumentNullException if values is null.


UseDefaultHistory

IMultiSelectControl<T> UseDefaultHistory()

Initializes the checked set from the most recent history entry (when EnableHistory is set), overriding any values supplied by Default. Has no effect when history is not enabled.


DefaultMatchBy

IMultiSelectControl<T> DefaultMatchBy(Func<T, T, bool> comparer)

Custom equality used to locate the Default items (and to compare items in general) — essential for records/classes where reference equality is not meaningful.

PromptPlus.Controls.MultiSelect<(int id, string City, string other)>("Cities")
    .Interaction(MyCities(), (r, c) => c.AddItem(r))
    .TextSelector(r => r.City)
    .DefaultMatchBy((a, b) => a.id == b.id)
    .Default([new(4, "New York", "any4")])
    .Run();

Throws ArgumentNullException if comparer is null.


Selection range

Range

IMultiSelectControl<T> Range(int minvalue, int? maxvalue = null)

Constrains how many items may be checked. minvalue is the minimum required at confirm time; maxvalue (optional) caps the maximum. The range is enforced on Enter: too few or too many checked keeps the list open and shows an error.

Argument Meaning
minvalue Minimum items that must be checked (0 = optional)
maxvalue Maximum items allowed; null (default) = no upper bound
PromptPlus.Controls.MultiSelect<string>("Cities", "Min. 2, Max. 3")
    .AddItems(["Seattle", "London", "Tokyo", "New York", "Singapore"])
    .Range(2, 3)
    .Run();

Throws ArgumentOutOfRangeException when minvalue < 0, or when maxvalue is specified and is less than minvalue.


Validating each check

Validation runs when the user checks an item (Space). On failure the check is rejected and the list shows an error.

PredicateChecked

IMultiSelectControl<T> PredicateChecked(Func<T, bool> validselect)
IMultiSelectControl<T> PredicateChecked(Func<T, (bool, string?)> validselect)
Overload Return Behavior
Func<T, bool> true = valid Generic error on failure
Func<T, (bool, string?)> (isValid, message) Custom message on failure
PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(["Seattle", "London", "Tokyo"])
    .PredicateChecked(city => city == "Tokyo"
        ? (true, null)
        : (false, "Only Tokyo can be selected"))
    .Run();

Mass operations — toggle-all (F2) and group-header Space — silently skip items the predicate rejects rather than showing an error.


PredicateCheckedAsync

IMultiSelectControl<T> PredicateCheckedAsync(Func<T, Task<bool>> validselect)
IMultiSelectControl<T> PredicateCheckedAsync(Func<T, Task<(bool, string?)>> validselect)

Asynchronous counterparts of the two PredicateChecked overloads.

⚠️ The async predicate is awaited synchronously (blocking) on the UI thread — keep it fast.


Read-only display

ViewOnly

IMultiSelectControl<T> ViewOnly(bool value = true)

Renders the list for viewing only — checks cannot be changed. Combine with Default (or AddItems(..., ischecked: true)) to show a fixed set of checked entries.

PromptPlus.Controls.MultiSelect<string>("Enabled features (read-only)")
    .AddItems(["Logging", "Caching", "Metrics"], ischecked: true)
    .ViewOnly()
    .Run();

Dynamic description

ChangeDescription

IMultiSelectControl<T> ChangeDescription(Func<T, string> value)

Recomputes the description from the currently focused item as the user navigates.

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(cities)
    .ChangeDescription(city => $"You are on: {city}")
    .Run();

ChangeDescriptionAsync

IMultiSelectControl<T> ChangeDescriptionAsync(Func<T, Task<string>> value)

Asynchronous version of ChangeDescription.


History

EnableHistory

IMultiSelectControl<T> EnableHistory(string filename, Action<IHistoryOptions>? options = null)

Persists confirmed selections to filename and can restore them (via Default or UseDefaultHistory). The IHistoryOptions builder is identical to the one documented for Input → EnableHistory (MinPrefixLength, MaxItems, ExpirationTime, FilterType, PageSize).

PromptPlus.Controls.MultiSelect<string>("Cities")
    .AddItems(cities)
    .EnableHistory("city-history", opt => opt.MaxItems(8).FilterType(FilterMode.StartsWith))
    .UseDefaultHistory()
    .Run();

Throws ArgumentNullException if filename is null.


Appearance & behavior

Styles

IMultiSelectControl<T> Styles(MultiSelectStyles styleType, Style style)

Recolors one visual region of this control. See the region list and examples on the Styles page.

using PromptPlusLibrary;
using ConsolePlusLibrary;   // Color, Style live here
PromptPlus.Controls.MultiSelect<string>("Cities").AddItems(cities)
    .Styles(MultiSelectStyles.Selected, new Style(Color.Blue, Color.Default))
    .Run();

Options

IMultiSelectControl<T> Options(Action<IControlOptions> options)

Overrides global behaviors for this one control (prompt/description text, abort key, tooltip, hide-after-finish, extra-info affixes). See Global Behaviors → Per-Control Override.

Throws ArgumentNullException if options is null.


Running the control

Run

ResultPrompt<T[]> Run(CancellationToken token = default)

Renders the list and blocks until the user confirms (Enter) or aborts (Esc). Returns ResultPrompt<T[]> — the array of checked items (an empty array when aborted or nothing was checked).

var result = PromptPlus.Controls.MultiSelect<string>("Cities").AddItems(cities).Run();

See also