Table of Contents

Class SelectingItemsControl

Namespace
Icy.UI.Controls
Assembly
IcyUI.dll

Adds single-item selection on top of ItemsControl - the shared base for Selector (adds a popup on top of this) and WrapGrid/ListBox (always-visible, no popup).

public abstract class SelectingItemsControl : ItemsControl, INotifyPropertyChanging, IBindingTarget, INotifyPropertyChanged, INotifyFocusChanged, IContainerLayout, IVirtualizingScrollInfo
Inheritance
SelectingItemsControl
Implements
Derived
Inherited Members
Extension Methods

Remarks

Realizes SelectorItems (see CreateContainer(DataTemplate, object)) instead of bare ItemContainers, and keeps each realized item's IsSelected in sync with SelectedIndex - including across a pool-and-reuse cycle, since a selected item's container can be de-realized and rebuilt later by virtualization.

Properties

ContainerIndices

Gets the reverse lookup from a realized SelectorItem back to the item index it's currently showing, so Container_Tapped(object, EventArgs) can turn a tap on the container into a SelectedIndex assignment. Kept in sync by AttachContainer(ItemContainer, int)/ DetachContainer(ItemContainer). Exposed to derived controls so Selector - whose own AttachContainer/DetachContainer override never calls this base implementation - can reuse the same map for its own (differently-triggered) tap handling instead of keeping a second, identically-shaped duplicate.

protected Dictionary<SelectorItem, int> ContainerIndices { get; }

Property Value

Dictionary<SelectorItem, int>

SelectedIndex

Gets or sets the currently selected item's index, or -1 for no selection.

[Range(-1, Infinity)]
[BindingOverride(BindingMode.TwoWay)]
public int SelectedIndex { get; set; }

Property Value

int

Remarks

An index past the current items doesn't throw: it's remembered, and selected as soon as the items cover it (until then SelectedIndex stays -1). So markup can set SelectedIndex="1" next to an ItemsSource binding that resolves only when the data context arrives. Setting SelectedIndex or SelectedItem again replaces the remembered index.

Exceptions

ArgumentOutOfRangeException

value is less than -1.

SelectedItem

Gets or sets the currently selected item, or null for no selection. Setting an item not present in ItemsSource clears selection instead of throwing.

[BindingOverride(BindingMode.TwoWay)]
public object? SelectedItem { get; set; }

Property Value

object

Methods

AttachContainer(ItemContainer, int)

Stamps a freshly realized container's IsSelected from SelectedIndex, on top of the base ItemsControl wiring - the case the SelectedIndex setter's own stamp (see its own realizedContainers lookup) can't reach: index selected before it's ever realized, or re-realized later after a pool-and-reuse cycle. Selector overrides this again itself, to route into its popup host instead of this base's default parenting.

protected override void AttachContainer(ItemContainer container, int index)

Parameters

container ItemContainer

The freshly realized container.

index int

The item index container was realized for.

Remarks

Also wires up click-to-select: subscribes Tapped (handled by Container_Tapped(object, EventArgs)) and records index in ContainerIndices so the handler can look it back up. This is inert for Selector and its subclasses (Dropdown, ComboBox), since their own AttachContainer override doesn't call this base implementation.

CreateContainer(DataTemplate, object)

Builds a fresh ItemContainer to host item's built visual tree - the default body RentContainer(DataTemplate, object) falls back to whenever pooling can't supply one. A Selector overrides this to realize SelectorItems instead.

protected override ItemContainer CreateContainer(DataTemplate template, object item)

Parameters

template DataTemplate

The template to build item's content with.

item object

The data item the new container is being realized for.

Returns

ItemContainer

The freshly built container.

DetachContainer(ItemContainer)

Exact inverse of AttachContainer(ItemContainer, int)'s click-to-select wiring - unsubscribes Tapped and forgets container's Icy.UI.Controls.SelectingItemsControl.containerIndices entry before deferring to the base detach.

protected override void DetachContainer(ItemContainer container)

Parameters

container ItemContainer

The container being de-realized.

OnContainerTapped(int)

Called when a realized container is tapped. Selects index by default.

protected virtual void OnContainerTapped(int index)

Parameters

index int

The tapped container's item index.

Remarks

A subclass whose items aren't all selectable (e.g. a tree whose category rows only expand) overrides this to decide what a tap does.

OnItemsChanged()

Called after items has been mutated by any means - a full ItemsSource reassignment (Icy.UI.Controls.ItemsControl.ResetItems()), a live incremental collection-change notification, or a full Reset re-snapshot. Empty by default. A subclass with state that depends on item identity/count (e.g. SelectingItemsControl's SelectedIndex) overrides this to keep it valid.

protected override void OnItemsChanged()

Remarks

Clears SelectedIndex (and SelectedItem with it) when the item it pointed to no longer exists because the live ItemsSource shrank out from under it, and selects an index set before the items covered it once they do.

OnSelectionChanged()

Called after SelectedIndex/SelectedItem have been updated, before the realized-container stamp and the public SelectionChanged event - empty by default. A subclass with derived state of its own that depends on the new selection (e.g. Selector's SelectedValue) overrides this to refresh it, rather than reacting to its own SelectionChanged subscription (which would depend on subscriber-ordering relative to any external subscriber this control's own consumer adds).

protected virtual void OnSelectionChanged()

Events

SelectionChanged

Occurs when SelectedIndex/SelectedItem changes.

public event EventHandler? SelectionChanged

Event Type

EventHandler