๐ท๏ธ ChipGroup
A row of toggle chips, all visible, bound to a key/value Items dictionary and a SelectedKeys collection.
๐ Overview
ChipGroup turns a handful of options into filter chips: "Error ยท Warning ยท Info ยท Debug", "Open ยท In progress ยท Done", product facets on a search page. It is faster than a drop-down when there are few options, and the state is visible at a glance. Each item is shown as a Chip; the group owns the selection, so SelectionMode, the selection limit and disabled keys apply to every click, key press and UI Automation call.
Highlights:
Multiple,Single(a radio group) orSingleOrNone(click the selected chip to clear it) selectionFilled(selected = accent fill) orOutlined(selected = accent border and tint) chips, in theChipsizes, with an optional check mark- Wrapping rows, one scrolling line, or a vertical column
- An optional leading All chip that selects or clears every enabled key in one change
- Optional icon and count per key ("Error 12") for facets
- A selection limit (
MaxSelectionCount) and disabled keys - One
SelectedKeysChangedevent per action;SelectedKeysis updated in place
For more than about 15 options use MultiSelectComboBox (little space) or CheckListBox (a side panel) instead.
๐ Namespace
using Atc.Wpf.Controls.DataDisplay;
xmlns:atc="https://github.com/atc-net/atc-wpf/tree/main/schemas"
๐ Usage
Log-level filter with counts and an All chip
<atc:ChipGroup
ItemCounts="{Binding LogLevelCounts}"
Items="{Binding LogLevels}"
SelectedKeys="{Binding SelectedLogLevels}"
ShowAllChip="True" />
public Dictionary<string, string> LogLevels { get; } = new()
{
["error"] = "Error",
["warning"] = "Warning",
["info"] = "Info",
["debug"] = "Debug",
};
public Dictionary<string, int> LogLevelCounts { get; } = new() { ["error"] = 12, ["warning"] = 48 };
public ObservableCollection<string> SelectedLogLevels { get; set; } = ["error", "warning"];
Status filter (outlined, single selection)
<atc:ChipGroup
ChipVariant="Outlined"
Items="{Binding Statuses}"
SelectedKeys="{Binding SelectedStatuses}"
SelectionMode="Single" />
One line that scrolls, or a vertical column
<atc:ChipGroup Items="{Binding Facets}" Wrap="False" />
<atc:ChipGroup
DisabledKeys="{Binding SoldOut}"
Items="{Binding Toppings}"
MaxSelectionCount="3"
Orientation="Vertical" />
Reacting to changes
chipGroup.SelectedKeysChanged += (_, e) =>
{
// e.OldValue and e.NewValue are the keys before and after the change.
};
โ๏ธ Properties
| Property | Type | Default | Description |
|---|---|---|---|
Items |
Dictionary<string, string> |
empty | Key โ display value. Changing it drops keys no longer present from SelectedKeys (one event). |
SelectedKeys |
ObservableCollection<string> |
empty | The selected keys. Two-way by default; updated in place; a new instance from the binding is picked up. |
SelectionMode |
ChipSelectionMode |
Multiple |
Multiple, Single (radio group) or SingleOrNone (click the selected chip to clear). |
SelectNewItems |
bool |
false |
Keys that appear in Items are selected automatically (Multiple only), up to MaxSelectionCount. |
ChipVariant |
ChipGroupVariant |
Filled |
Filled: selected = accent fill. Outlined: selected = accent border and a light accent tint. |
ChipSize |
ChipSize |
Medium |
Small, Medium or Large, as Chip. |
ShowCheckMark |
bool |
true |
A โ before the text of a selected chip. |
Orientation |
Orientation |
Horizontal |
The direction the chips are laid out in. |
Wrap |
bool |
true |
false keeps the chips on one line that scrolls. |
ItemSpacing |
double |
4 |
Space between two chips and between two lines. |
ShowAllChip |
bool |
false |
A leading All chip (Multiple only): selected when every enabled key is; clicking it selects them all or clears them in one change. |
MaxSelectionCount |
int? |
null |
The most keys that can be selected (Multiple); at the limit the other chips are disabled, not hidden. null (no limit) or at least 1; a lower value throws an ArgumentException. |
DisabledKeys |
ObservableCollection<string> |
empty | Keys whose chips are shown but cannot be toggled. |
ItemIcons |
Dictionary<string, object>? |
null |
Optional icon per key (font icon, image, any content). |
ItemCounts |
Dictionary<string, int>? |
null |
Optional count per key, shown after the text ("Error 12"). |
๐ก Events
| Event | Args | When |
|---|---|---|
SelectedKeysChanged |
ValueChangedEventArgs<IReadOnlyList<string>> |
Each toggle; the All chip, an arrow key in a single-select group and an Items change that drops or adds keys are one event each. Changes made to SelectedKeys from outside raise none. |
๐งฉ Methods
| Method | Description |
|---|---|
SelectAll() |
Selects every enabled chip in one change (Multiple only; nothing happens when the limit has no room). |
ClearSelection() |
Clears every enabled chip in one change. |
โจ๏ธ Keyboard and UI Automation
Tabenters and leaves the group as one stop.Multiple: arrow keys move the focus,Space/Entertoggles the focused chip,Ctrl+Aselects all.Single/SingleOrNone: the group is a radio group; arrow keys move and select. Disabled chips are skipped.- The group is a list. In
Multipleeach chip is a check box with the Toggle pattern; in the single modes each chip is a radio button with the SelectionItem pattern and the group has the Selection pattern. A chip's name is its display value.
๐ Notes
- When
SelectedKeysis data-bound, the keys dropped (or ticked) becauseItemschanged are written once the bindings have settled (one dispatcher pass later), so a DataContext swap never writes into the previous view model's collection; unbound, it happens at once. After a DataContext swapSelectNewItemsticks nothing in the new view model (its keys were never shown against the old items), and a cleanup requested while the control is unloaded runs when it is loaded again. - Only the keys of items that disappear from
Itemsare dropped; keys that were never among the items are kept, so a selection restored before the items load (an emptyItemsfirst, the loaded items later) survives. The whole family follows this rule. - Material guidance: a chip set is either single- or multi-select, never mixed โ so
ShowAllChip,MaxSelectionCountandSelectNewItemsonly apply inMultiplemode. - Switching from
Multipleto a single mode keeps only the most recently selected key (oneSelectedKeysChanged; with a data-boundSelectedKeys, once the bindings have settled), likeSegmented. - In the single modes a
SelectedKeysset from outside with several keys is shown as is; the next click or arrow key leaves one key. - An icon element in
ItemIconscan only be on one chip; use one element per key. - Theme brushes only; the chips follow Light, Dark and right-to-left (arrow keys follow the flow direction).
๐ Related Controls
- Chip - A single chip;
ChipGroupuses it for every item - LabelChipGroup - The same group with a label, mandatory marker and validation
- MultiSelectComboBox - Drop-down with check boxes, for 3โ1,000 items and little space
- TokenBox - Large or open-ended sets, typing is the main way in
- CheckTreeView / TreeSelectComboBox - Hierarchies with tri-state check boxes
- Segmented - 2โ6 very short options as a joined button row
- CheckListBox - Always-visible check list for 5โ1,000 items
- DualListSelector - Building an ordered list out of a pool
- CardSelector - Few, visual choices
๐ฎ Sample Application
See the sample application under Wpf.Controls > Data Display > ChipGroup.