WPF Standard Control Demo App › Expander

Expander Display

Expander shows a header at all times and shows or hides its content when the header is clicked.

What collapsed content costs

Expander derives from HeaderedContentControl. Its Content is what is shown and hidden, and collapsed content costs less than it may seem. In an Expander collapsed from the start, the content element was created and received Loaded, but it was not measured. A ListBox of 1000 items inside it created no ListBoxItem at all: in this setup, the list created and measured no item containers until the Expander was expanded, although the content element itself was created and loaded. After expanding, the content was measured, the ListBox created 11 items, and Loaded was raised on the content a second time. Do not start heavy work in the content’s Loaded handler: it runs while the Expander is collapsed, and again when it is expanded.

Expanding and collapsing, with no animation

IsExpanded decides whether the content is shown; the default is False. It binds two-way by default, so a view model property bound to it follows the user’s clicks. The demo app binds it to a check box without a Mode, so the two stay in step. A click on the header with the real mouse expanded the Expander, checked the box, and raised Expanded. Clearing the box collapsed it and raised Collapsed.

The header in the default template is a ToggleButton named HeaderSite. The template has no visual state groups and no animation: it switches with triggers on IsExpanded, ExpandDirection, and IsEnabled. When IsExpanded was set to False, the content was Collapsed at once. To animate, use a template of your own.

case measured
base class / IsExpanded default, two-way by default / ExpandDirection HeaderedContentControl / False, True / Down
default template: header element / VisualStateGroups ToggleButton named HeaderSite / 0
triggers IsExpanded=True; ExpandDirection=Right, Up, Left; IsEnabled=False
IsExpanded set to False: content Visibility at once / after 50 ms Collapsed / Collapsed
real mouse click on header: IsExpanded / bound CheckBox / events True / True / Expanded
then the CheckBox cleared: IsExpanded / events False / Collapsed
collapsed: child Loaded / measured / items in a 1000-item ListBox 1 / 0 / 0
after expanding 2 / 1 / 11

The template, clicks, and collapsed content. Measured on .NET 10 / Windows 11.

Where the header and the content go

ExpandDirection decides where the content appears relative to the header; the default is Down. With a content 80 × 40, Down placed the header on top and the content below it, and Up placed the content above the header. With Left and Right, the header became a column beside the content, 49 wide and 39 high, with its text still horizontal in the lower part of the column. The content was on the left for Left and on the right for Right.

HasHeader is read-only and tells whether there is a Header. With Header null, HasHeader was False, but the header’s ToggleButton, with its arrow, stayed visible, 19 high. Hiding it takes a template of your own.

Properties that reach the header as well as the content

The Control properties set on the Expander apply to the header too, not only to the content.

case measured
ExpandDirection=Down: header / content / header text x=2 y=2 w=116 h=19 / x=20 y=22 w=80 h=40 / x=25 y=3.52 w=49.04 h=15.96
ExpandDirection=Up: header / content / header text x=2 y=42 w=116 h=19 / x=20 y=1 w=80 h=40 / x=25 y=43.52 w=49.04 h=15.96
ExpandDirection=Left: header / content / header text x=82 y=2 w=49.04 h=38.96 / x=1 y=1.48 w=80 h=40 / x=82 y=25 w=49.04 h=15.96
ExpandDirection=Right: header / content / header text x=2 y=2 w=49.04 h=38.96 / x=52.04 y=1.48 w=80 h=40 / x=2 y=25 w=49.04 h=15.96
Header=null: HasHeader / header ToggleButton Visibility, size False / Visible, 196 x 19
FontWeight=Bold, Foreground=Red: header text / content text Bold, #FFFF0000 / Bold, #FFFF0000
Background: painted area / header / content (inside it) x=0 y=0 w=200 h=38.96 / x=2 y=2 w=196 h=19 / x=1 y=22 w=198 h=15.96 (True)
Padding=0, BorderThickness=0: header / content x=1 y=1 w=198 h=19 / x=60 y=21 w=80 h=40
Padding=20, BorderThickness=0: header / content x=1 y=1 w=198 h=59 / x=60 y=81 w=80 h=40
Padding=0, BorderThickness=5: header / content x=6 y=6 w=188 h=19 / x=60 y=26 w=80 h=40

ExpandDirection, the header, and the Control properties. Measured on .NET 10 / Windows 11.

Trying it in the demo app

The Expander page of the demo app, with the control list on the left and the first section, ExpandDirection

The Expander page of the demo app has sections for ExpandDirection, IsExpanded, the header, the content, and the Control properties Padding, the font properties, Background, Foreground, and the border. The header section turns an empty text box into null. The “Show Code” link under each section displays its XAML. The following XAML is the IsExpanded section (ExpanderUsageControl.xaml), with the styles and the surrounding GroupBoxes left out and the namespace declarations added:

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <CheckBox x:Name="IsExpandedCheckBox" VerticalContentAlignment="Center" Content="IsExpanded" />

  <Expander x:Name="IsExpandedExpander"
            Content="CONTENT"
            Header="Expander"
            IsExpanded="{Binding IsChecked, ElementName=IsExpandedCheckBox}" />
</StackPanel>

Source code and how it was measured

Every behavior on this page was measured by running it on .NET 10 / Windows 11, using ExpanderDemoScene in this site’s screenshot tool. The click on the header was made with the real mouse over the measuring window. Positions are measured from the Expander’s top-left corner, and sizes are the values on the measuring machine.

View Expander source code on GitHub →