WPF Standard Control Demo App › TabControl

TabControl Selectors

TabControl is a container that organizes content into multiple pages, each represented by a TabItem. Users switch between pages by clicking on the tab headers. It is the primary control for tabbed interfaces such as settings dialogs, workspace panels, and multi-view editors.

Overview

The WPF TabControl derives from Selector, which derives from ItemsControl. This means its items collection can be populated directly with TabItem elements in XAML or data-bound via ItemsSource with an ItemTemplate and ContentTemplate. Only the content of the currently selected tab is rendered, keeping memory usage low for tabs with complex layouts.

The TabStripPlacement property controls which edge of the control hosts the tab headers. Top (default) is the most familiar; Left and Right produce vertical tab strips suitable for settings panels with many categories. Bottom placement is less common but sometimes used in code editors or browser-style interfaces.

When binding to a collection, use the SelectedItem or SelectedIndex properties (inherited from Selector) to track and control the active tab in the ViewModel. Setting SelectedIndex to an integer is useful for programmatic tab navigation, while SelectedItem works naturally with object collections.

TabControl supports lazy content loading through the ContentTemplate approach. Because only the active tab's content is measured and rendered, large or expensive views (such as charts or data grids) inside inactive tabs are not created until the user first selects them, significantly improving initial load performance.

Screen Preview

tabcontrol demo screen

Demonstrated Properties

The following properties are demonstrated interactively in the WPF Standard Control Demo App. Each property can be configured in real time within the app to observe its behavior.

PropertyValuesDescription
TabStripPlacement Top / Bottom / Left / Right When to use: Use Left for Outlook-style navigation panels or settings dialogs that have many categories โ€” vertical strips scale better when there are more than five or six tabs. Use Top (the default) for standard dialogs with a small number of pages.
What happens: The tab header strip moves to the specified edge of the control. With Left or Right, headers stack vertically. Content area layout adjusts accordingly.
Pitfalls: When using Left or Right, header text remains horizontally oriented but is displayed in a vertical list, so each header occupies its natural text width. With many long-named tabs the strip can become very wide; set MinWidth or MaxWidth on the item container style to control this.
SelectedIndex / SelectedItem int / object When to use: Bind two-way to the ViewModel to control the active tab programmatically โ€” for example, in a wizard where a "Next" button advances to the next step, or a navigation service that opens a specific tab by name.
What happens: Setting SelectedIndex switches the active tab to the specified zero-based position. Setting it to -1 deselects all tabs and leaves the content area empty. Setting SelectedItem selects the matching tab item object.
Pitfalls: Out-of-range index values are silently ignored โ€” no exception and no selection change. Similarly, setting SelectedItem to an object not present in ItemsSource does nothing. Always verify the value is valid before applying it.
ItemsSource IEnumerable When to use: Use when the set of tabs is determined at runtime from a ViewModel collection โ€” for example, a list of open documents or a dynamic set of configuration categories.
What happens: Each item in the collection is wrapped in a TabItem container. Define HeaderTemplate to control how the tab header looks for each data object, and ContentTemplate for the tab's content area.
Pitfalls: ItemsSource and static TabItem children in XAML are mutually exclusive. If you set ItemsSource, you cannot also add TabItem elements directly in the XAML markup โ€” doing so throws a runtime exception.
Header / IsEnabled (TabItem) object / bool When to use: Use IsEnabled="False" to restrict access to a tab based on user permissions or wizard prerequisites โ€” the tab appears grayed out and is not clickable.
What happens: Setting IsEnabled="False" grays out the tab header so users cannot click it. Header accepts any WPF element, enabling rich labels with icons or badges.
Pitfalls: IsEnabled="False" only prevents user interaction โ€” it does not prevent programmatic access. Code can still switch to a disabled tab by setting SelectedIndex or SelectedItem. If access control is a security requirement, enforce it on the content side as well.
ContentStringFormat string A format string applied to the selected content when it is a simple type displayed as text. Follows the same pattern as String.Format, e.g., "Value: {0}". Used when ContentTemplate is not defined and content is a string or number.
SelectedContent (ReadOnly) object The content object of the currently selected tab. Read-only; reflects which TabItem is active. Bind to this in the ViewModel if other parts of the UI need to react to the currently displayed content.

XAML Example

A settings dialog with left-positioned tabs and MVVM-bound tab switching:

<TabControl TabStripPlacement="Left"
            SelectedIndex="{Binding ActiveTabIndex, Mode=TwoWay}">
  <TabItem Header="General">
    <StackPanel Margin="16">
      <CheckBox Content="Enable auto-save" IsChecked="{Binding AutoSave}" />
    </StackPanel>
  </TabItem>
  <TabItem Header="Appearance">
    <StackPanel Margin="16">
      <Label Content="Theme:" />
      <ComboBox ItemsSource="{Binding Themes}"
                SelectedItem="{Binding SelectedTheme}" />
    </StackPanel>
  </TabItem>
  <TabItem Header="Advanced">
    <TextBlock Text="Advanced settings here." Margin="16" />
  </TabItem>
</TabControl>

Common Use Cases

Tips and Best Practices

Related Controls

Source Code

The source code for this demo screen is available on GitHub. Use the built-in code view buttons in the app to see the exact XAML for each property.

View TabControl source code on GitHub →