Table of Contents

Class TabControl

Namespace
Icy.UI.Controls
Assembly
IcyUI.dll

A row of clickable tab headers, each showing/hiding its own Content - realizes each TabItem's header as a SelectorItem via the inherited SelectingItemsControl machinery, but never scrolls: unlike ListBox/ WrapGrid, this control doesn't participate in IVirtualizingScrollInfo's viewport-driven realize pipeline at all - it eagerly realizes every header itself, since a handful of tab headers never need virtualizing.

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

Remarks

ItemsSource holds TabItem objects. CreateContainer(DataTemplate, object) is overridden to build each header's StackPanel+Icon+ContentPresenter tree directly in code from Header/Icon, rather than going through ItemTemplate/markup - this control has no dependency on any caller-supplied ItemTemplate, and doesn't offer one as a header-customization hook (a caller who wants a different header layout composes a custom Header instead).

Chrome stays the plain decorative Border spanning this control's whole ActualBounds (the same convention every ItemsControl subclass already follows - realized items are extra visual children, not Chrome's child). A second, separately-managed ContentPresenter child (outside Chrome, mirroring Content's own "extra managed child" shape) shows the selected Content, below the header row.

Constructors

TabControl()

Initializes a new instance of the TabControl class.

public TabControl()

Methods

ArrangeContent()

Handles custom arrange logic when overridden in any UIElement instance.

protected override void ArrangeContent()

Remarks

This method is called during the arrange pass to position and size the element's content within its final bounds. The element's position and size are already determined by the layout system and available in the ActualBounds property.

When implementing this method:

  • Position child elements within the available space;
  • Respect the element's padding when positioning content;
  • Handle any content-specific layout requirements;
  • Call Arrange() on child elements if needed.

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)

Creates the header container for a tab.

protected override ItemContainer CreateContainer(DataTemplate template, object item)

Parameters

template DataTemplate

Unused - see the class remarks.

item object

The TabItem the new header is being realized for.

Returns

ItemContainer

A freshly built SelectorItem hosting the header's visual tree.

Remarks

Builds the header's visual tree directly in code - a StackPanel holding the source Icon (when set) followed by a ContentPresenter wrapping Header - instead of going through template (see the class remarks for why template is otherwise unused here).

GetVisualChildren()

Enumerates this element's immediate visual children, in paint order (back-to-front), for hit-testing and tree traversal.

protected override IEnumerable<UIElement> GetVisualChildren()

Returns

IEnumerable<UIElement>

The element's immediate children. The base implementation yields none (a leaf element).

Remarks

Container elements (e.g. Panel, Border) override this to expose their children, in the exact order they're drawn in — HitTest(Vector2) depends on this matching actual paint order, or clicks will target the wrong, visually-obscured element.

MeasureContent()

Handles custom measure logic when overridden in any UIElement instance.

protected override Size MeasureContent()

Returns

Size

Size recommended to display the UIElement.

Remarks

This method is called during the measure pass to determine the desired size of the element. The returned size should represent the natural size of the element's content, without considering any constraints, margins, or padding.

When implementing this method:

  • Return the natural size needed to display the content;
  • Do not include padding, margins, or borders in the returned size;
  • Consider the content's actual dimensions (e.g., text length, image size);
  • Return Empty if the element has no content.

OnAttached()

Raises the Attached event.

protected override void OnAttached()

Remarks

Propagates Canvas to every element in GetVisualChildren() - this is what makes attaching a whole pre-built subtree (the common pattern: build children, then attach the root once via Add(UIElement)) reach every descendant, not just the immediate root. Each child's own Canvas setter recurses into its children the same way, so this walks the full subtree regardless of depth. Container-specific child-add paths (e.g. OnChildAdded(object?, GenericEventArgs<UIElement>)) still assign Canvas directly for children added after the parent is already attached - this cascade is what covers everything built beforehand.

OnDetached()

Raises the Detached event.

protected override void OnDetached()

Remarks

Propagates null to every element in GetVisualChildren(), mirroring OnAttached() - see its remarks.

OnRender(IRenderContext)

Handles custom render logic when overridden in any UIElement instance.

protected override void OnRender(IRenderContext context)

Parameters

context IRenderContext

The context to render with.

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 override void OnSelectionChanged()