Table of Contents

Class Expander

Namespace
Icy.UI.Controls
Assembly
IcyUI.dll

A collapsible region: a clickable Header row that shows/hides arbitrary Content below it, with an animated expand/collapse transition driven entirely by the existing themed VisualState system (see ExpansionProgress).

[ContentProperty("Content")]
public class Expander : Control, INotifyPropertyChanging, IBindingTarget, INotifyPropertyChanged, INotifyFocusChanged, IContainerLayout
Inheritance
Expander
Implements
Inherited Members
Extension Methods

Remarks

The clickable header is a composed ExpanderHeader (a plain ToggleButton subtype), exposed as a named template part - PART_Header - the same way Slider exposes PART_Thumb and SplitPane exposes PART_Divider. All of the header's hover/press/click/checked behavior comes from ToggleButton for free; Expander itself never handles pointer input directly.

Content lives outside Chrome, managed directly by Expander (mirrors First/Second) - needed because Background/etc.'s hard (Border)Chrome cast means the single Chrome.Child slot can only hold one more visual, and that slot is already the header.

Constructors

Expander()

Initializes a new instance of the Expander class.

public Expander()

Properties

Content

Gets or sets the element shown/hidden below Header as IsExpanded toggles.

public UIElement? Content { get; set; }

Property Value

UIElement

Remarks

Skipped entirely (no measure, arrange, draw, or hit-test) while fully collapsed and idle - see ExpansionProgress.

ExpansionProgress

Gets or sets how far along the expand/collapse transition Content is, from 0 (fully collapsed) to 1 (fully expanded).

public float ExpansionProgress { get; set; }

Property Value

float

Remarks

A themable data slot (mirrors CheckBrush/ThumbBrush's own shape) - normally driven by a themed VisualState transition on Expanded rather than set directly, though nothing prevents a custom theme (or an untemplated caller) from doing so for an instant, non-animated toggle. Drives Content's own IsVisible, and how much of it ArrangeContent() reveals.

Header

Gets or sets the element displayed in the always-visible header row, before the collapsible Content.

public UIElement? Header { get; set; }

Property Value

UIElement

IsExpanded

Gets or sets a value indicating whether Content is shown.

[BindingOverride(BindingMode.TwoWay)]
public bool IsExpanded { get; set; }

Property Value

bool

Remarks

Setting this sets/clears Expanded, which a themed VisualState transition uses to animate ExpansionProgress from 0 to 1 (or back) - see the class remarks. Mirrors IsChecked's own shape, and is kept two-way synchronized with the internal header toggle's own IsChecked (clicking the header sets this; setting this also checks/unchecks the header).

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.

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.

OnApplyTemplate()

Called once, every time Template changes (in either direction - applied, cleared, or switched to a different template), right after Chrome and every decoration/content property have been fully re-wired for the new state.

protected override void OnApplyTemplate()

Remarks

Does nothing by default. A subclass that reaches into its own visual tree by reference - e.g. Slider wiring its drag logic directly to its thumb element - overrides this to call GetTemplateChild<T>(string) and repoint that reference to whatever the new Template (or, when reverting, the fresh default Border) actually provides, instead of hardcoding it once at construction. This is what actually makes a control "template-safe": until a control overrides this appropriately, applying a custom Template to it silently orphans whatever elements its own code still holds direct references to.

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.

Events

IsExpandedChanged

Occurs when IsExpanded changes.

public event EventHandler? IsExpandedChanged

Event Type

EventHandler