For the complete documentation index, see llms.txt. This page is also available as Markdown.

ListBox

Introduction

The ListBox control provides a scrollable list of ListBoxItems for displaying and selecting from a list.

ListBox inherits from ScrollViewer, so it supports the same scrolling behavior. This includes the MouseWheelScrollSpeed property, which controls how far the list scrolls per mouse-wheel notch. For details see Mouse Wheel Scroll Speed on the ScrollViewer page.

Code Example: Adding a ListBox

The following code adds items to a ListBox when a button is clicked. When an item is added, ScrollIntoView is called so the item is shown.

// Initialize
var listBox = new ListBox();
listBox.AddToRoot();
listBox.X = 50;
listBox.Y = 50;
listBox.Width = 400;
listBox.Height = 200;

var button = new Button();
button.AddToRoot();
button.X = 50;
button.Y = 270;
button.Text = "Add to ListBox";
button.Click += (s, e) =>
{
    var newItem = $"Item {listBox.Items.Count} @ {DateTime.Now}";
    listBox.Items.Add(newItem);
    listBox.ScrollIntoView(newItem);
};

Try on XnaFiddle.NET

Adding items to a ListBox by clicking a button

Items

The Items property contains the data that is displayed by the ListBox. Whenever an object is added to Items, the ListBox creates a ListBoxItem instance.

Any object can be added to Items. By default, ToList is called on any added item. The following code shows how int and string instances can be added and mixed in a ListBox:

Try on XnaFiddle.NET

Items added to a ListBox

Adding ListBoxItems to Items

If a ListBoxItem is added directly to the Items property, then the ListBox uses this ListBoxItem directly rather than creating a new ListBoxItem. This simplifies the creation of ListBoxItems.

For example, the following code shows how to create ListBoxItems with custom colors:

Try on XnaFiddle.NET

ListBoxItems directly added

Removing Items

Items can be removed by reference with Remove, by index with RemoveAt, or all at once with Clear.

The following code adds a remove button that deletes the currently selected item from the ListBox.

Try on XnaFiddle.NET

Selection

ListBox items can be selected. The ListBox class provides a number of ways to work with the selection.

Selection can be set by index:

Item can also be selected by the reference itself, assuming the referenced item is part of the list box:

Selection can be cleared by setting SelectedIndex to -1:

Whenever the selection changes, the SelectionChanged event is raised:

Multi-Selection

Multi-selection can be controlled through the SelectionMode property.

Try on XnaFiddle.NET

Accessing Multiple Selections

When using SelectionMode.Multiple or SelectionMode.Extended, you can access all currently selected items using the SelectedItems property. This property returns a System.Collections.IList containing the selected objects.

The SelectedObject and SelectedIndex properties are still available, but they will only return the first item in the selection.

The following code shows how to iterate over all selected items:

Keyboard and Gamepad Navigation

A ListBox uses a two-level focus model:

  • Top-level focus — the ListBox itself is focused (IsFocused is true). In this state, input moves focus between controls (tabbing), not within the list. This is the state a ListBox is in right after you set IsFocused = true.

  • Item-level focus — focus has moved into the list (DoListItemsHaveFocus is true). Now the up and down arrow keys and the d-pad move the highlighted item, and the SelectionChanged event fires as the selection changes.

By default the user moves from top-level to item-level focus by pressing the confirm input — Enter on the keyboard, or the A button on a gamepad. This is the extra "enter the list" press.

Starting directly on an item

To skip that press and have the list start with an item already focused — navigable immediately by the arrow keys or d-pad — set SelectedIndex first, then set DoListItemsHaveFocus to true:

Try on XnaFiddle.NET

Setting DoListItemsHaveFocus = true also forces IsFocused = true, so you do not need to set both.

Controlling how focus leaves the items

Two properties control how focus exits item-level navigation:

  • CanListItemsLoseFocus (default true) — when true, pressing the back/cancel input (the B button) returns focus to the top level. Set this to false when the ListBox is the only focusable control on the screen, so focus can never leave the items. Setting it to false while the ListBox is focused also moves focus into the items immediately.

  • LoseListItemFocusOnPrimaryInput (default true) — when true, the confirm input (A button / Enter) selects the highlighted item and returns focus to the top level. Set this to false when the confirm input should act on the item — for example toggling a CheckBox in a custom item template — without leaving item-level focus.

For the specific keys and buttons each input device uses, see Keyboard Support and Gamepad Support.

Reordering With Drag+Drop

The DragDropReorderMode controls whether the user can automatically reorder ListBoxItems by pushing on an item and dragging it to a new location. By default this value is set to NoReorder, but it can be changed to enable reordering.

The following code creates a ListBox which supports reordering:

Try on XnaFiddle.NET

ListBoxItems reordering

Decorations and Separators

A decoration is an inert visual — a separator line, a group header, or other chrome — that renders between rows but is not part of the list's data. A decoration lives in the ListBox's InnerPanel.Children alongside the row visuals, so it appears inline between items, but it belongs to neither Items nor ListBoxItems. As a result:

  • SelectedIndex and SelectedObject stay contiguous. The row after a decoration keeps its data index, so adding a decoration never shifts your indices.

  • A decoration can never be selected, clicked to select, or reached by keyboard or gamepad navigation. Clicking it does nothing, and arrow or d-pad navigation skips over it.

Adding a Separator Between Groups

A thin, filled horizontal line makes a natural separator. Build one from any inert visual — a RectangleRuntime works well — and anchor it to a data item with InsertDecorationAfter (or InsertDecorationBefore):

Anchoring and Lifetime

A decoration is anchored to a data item, not to a fixed position:

  • It follows its anchor item when the list is reordered — including the drag-and-drop reordering described in Reordering With Drag+Drop above.

  • It is automatically removed when its anchor item is removed from Items.

The three add methods differ only in how the anchor is chosen:

Method
Anchor

AddDecoration(visual)

The item that is currently last in Items (the "add now" case). Items added afterward appear below the decoration. If Items is empty, the decoration is placed at the end of the panel.

InsertDecorationAfter(item, visual)

Immediately after the given item's row.

InsertDecorationBefore(item, visual)

Immediately before the given item's row.

InsertDecorationAfter and InsertDecorationBefore throw an ArgumentException if the anchor item is not in Items. Call RemoveDecoration(visual) to take a decoration out manually; it returns true if the visual was a tracked decoration. Re-adding a decoration that is already tracked re-anchors it rather than adding it twice.

Because decorations stay out of Items, binding a ListBox to a typed ObservableCollection<T> remains valid with decorations present — the bound collection only ever contains your data objects. See Items Binding (ListBox, ComboBox, ItemsControl).

The decoration methods are defined on ItemsControl / ListBox, so they are available on every runtime. The visual you pass in is your own: any GraphicalUiElement works, so pick a type your platform provides (for example a RectangleRuntime on MonoGame/KNI/FNA/Raylib).

Customizing with VisualTemplate

The VisualTemplate lets you customize the type of ListBoxItem created for the ListBox. The following code shows how to assign a VisualTemplate to a runtime object named CustomListBoxItemRuntime:

The VisualTemplate class can optionally pass a parameter representing the item in the list box. This can be used to create different types of items based on the object added. For example the following code would compare the passed object as an integer to whether it is greater than 100 and returns a different item depending on this result:

Note that the code above uses the item to decide which type of list box item to create. If your list box item needs to react to changes on the item, you can also pass the item in the constructor to your list box. This allows for additional initialization based on the item. You can also hold on to the reference of the item to react to changes that may happen on the item, or to push changes to the item.

In other words, you are free to use the item for your game's needs; however, keep in mind that UpdateToObject will be called after your ListBoxItem is constructed. For more information on how to customize UpdateToObject, see the section below.

Customizing Displayed Property with ListBoxItemFormsType

By default the ListBox calls ToString on each item. This is usually okay if you are dealing with primitive types. For example, the following code adds sequential integers to a ListBox:

ListBox displaying integers

Often you may want to add a list of items which should not use their ToString method. For example you may have a list of IDs which represent weapons in a dictionary. The display can be customized by inheriting from ListBoxItem as shown in the following code:

Sizing to Children

ListBoxes can be sized to their children. If using code-only, then the ListBoxVisual can be obtained by casting to call MakeHeightSizedToChildren.

Try on XnaFiddle.NET

Sizes can also be limited by setting the maximum size of the ClipContainer:

Last updated

Was this helpful?