Controls

ItemsPresenter

ItemsPresenter is the template-level host for an ItemsControl's realized item containers. It does not generate items, choose templates, or own a collection by itself. Its job is to expose the owning control's existing item visuals and arrange them as one vertical stack.

Quick start

Use ItemsPresenter inside a ControlTemplate when you want the repeated item visuals from an ItemsControl, ListBox, TreeView, or another derived items control to appear at a specific spot in the template.

Minimal items host in a template

<Style TargetType="{x:Type ItemsControl}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <ItemsPresenter />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Framed item list

<Style x:Key="FeedStyle" TargetType="{x:Type ItemsControl}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <Border Background="#101822"
                BorderBrush="#2D465E"
                BorderThickness="1"
                Padding="12">
          <ItemsPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Items host inside a scroll viewer

<Style x:Key="ScrollableItemsControlStyle" TargetType="{x:Type ItemsControl}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <ScrollViewer Padding="8">
          <ItemsPresenter />
        </ScrollViewer>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Default mental model: ItemsPresenter is a placement marker for item visuals that already belong to an items control. Think "render the owner's realized items here," not "this is a standalone repeater."

What it does and what it does not do

What it does

Finds an owning ItemsControl, attaches to that owner as the active item host, and exposes the owner's realized item containers as its own visual and logical children.

What it does not do

It does not create containers, evaluate ItemTemplate, manage ItemsSource, support an ItemsPanel property, or introduce a custom layout algorithm.

  • The owning ItemsControl still decides which item containers exist.
  • The presenter only changes where those realized containers are parented and measured.
  • If no owner is found, the presenter has no children and reports a desired size of zero.
  • When an owner is found, that owner reparents realized item containers under the presenter.

Owner discovery

ItemsPresenter locates its owner by walking up the logical or visual tree until it finds the nearest ancestor ItemsControl. That makes it a natural fit inside control templates, where the presenter lives somewhere beneath the templated items control.

Typical template relationship

<ControlTemplate TargetType="{x:Type ItemsControl}">
  <Border Background="#16212D"
          BorderBrush="#34506C"
          BorderThickness="1"
          Padding="10">
    <ItemsPresenter />
  </Border>
</ControlTemplate>

In that arrangement, the presenter finds the surrounding ItemsControl, calls into it as the active host, and the owner moves its realized item containers under the presenter.

Practical rule: place ItemsPresenter under the items control whose items you want to show. If you move it outside that ownership chain, it will not find the correct source of realized items.

Layout behavior

The layout contract is fixed and intentionally simple. This implementation always measures and arranges realized item containers as a vertical stack.

Measure

Every realized container is measured using the same available size. The presenter's desired width becomes the maximum child width, and its desired height becomes the sum of child heights.

Arrange

Children are arranged top to bottom in realization order. Each child gets the full final width of the presenter and keeps its own measured height.

  • Desired width = maximum realized item desired width.
  • Desired height = sum of realized item desired heights.
  • Each arranged child gets finalSize.X as its width.
  • The first child starts at the presenter's top edge; later children are placed immediately below the previous one.
<ItemsControl ItemsSource="{Binding Logs}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border Background="#172331"
              BorderBrush="#2B4259"
              BorderThickness="1"
              Padding="10"
              Margin="0,0,0,8">
        <TextBlock Text="{Binding Message}" />
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

Those generated item visuals remain vertically stacked whether the hosting template uses the presenter's default position directly or wraps it in other containers such as Border or ScrollViewer.

No ItemsPanel abstraction

WPF developers often expect ItemsPresenter to hand off layout to an ItemsPanel. That is not how this framework currently works. The presenter itself performs the vertical stacking behavior.

Supported expectation

Use the presenter to decide where repeated visuals appear inside a template.

Unsupported expectation

Do not expect swapping in a panel type such as WrapPanel or UniformGrid through an ItemsPanel property.

Framework-specific behavior: collection layout is vertically stacked by the owner or by ItemsPresenter. If you need a different collection layout contract, that requires a different control implementation rather than a presenter setting.

How it interacts with item generation

ItemsPresenter works with already realized item containers from the owning items control. That means templating, fallback container creation, grouping, and item container styling are still controlled by the owner.

Templates

ItemTemplate and ItemTemplateSelector are resolved by the owning ItemsControl before the presenter lays anything out.

Fallback containers

If the owner creates generated Label containers for plain data, those labels are what the presenter hosts.

Grouping

If the owner projects grouped visuals through GroupItem containers, the presenter hosts those group containers instead of the raw item containers.

Template-driven list with generated item visuals

<Style x:Key="NotificationsStyle" TargetType="{x:Type ItemsControl}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <Border Background="#0F1822"
                BorderBrush="#2F475F"
                BorderThickness="1"
                Padding="12">
          <ItemsPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<ItemsControl Style="{StaticResource NotificationsStyle}"
              ItemsSource="{Binding Notifications}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border Background="#172331"
              BorderBrush="#35516B"
              BorderThickness="1"
              Padding="10"
              Margin="0,0,0,8">
        <StackPanel>
          <TextBlock Text="{Binding Title}" Margin="0,0,0,4" />
          <TextBlock Text="{Binding Message}" />
        </StackPanel>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

Property surface

ItemsPresenter does not add new public dependency properties of its own. You mainly work with it through placement and inherited FrameworkElement properties.

Inherited layout properties

Properties such as Width, Height, Margin, HorizontalAlignment, and VerticalAlignment affect the presenter's own slot like any other framework element.

No presenter-specific knobs

There is no public ItemsPanel, spacing, orientation, or container-generation property on this type.

Most customization happens around the presenter rather than on it. Typical examples include wrapping it in a Border, placing it in a ScrollViewer, or changing the owner's ItemTemplate.

Patterns and examples

Minimal template placeholder

<ControlTemplate TargetType="{x:Type ListBox}">
  <ItemsPresenter />
</ControlTemplate>

Scrollable list shell

<ControlTemplate TargetType="{x:Type ItemsControl}">
  <Border Background="#111922"
          BorderBrush="#35516B"
          BorderThickness="1">
    <ScrollViewer Padding="10">
      <ItemsPresenter />
    </ScrollViewer>
  </Border>
</ControlTemplate>

Grouped view with a custom shell

<ItemsControl ItemsSource="{StaticResource TasksView}">
  <ItemsControl.GroupStyle>
    <GroupStyle HeaderStringFormat="{0}" />
  </ItemsControl.GroupStyle>
  <ItemsControl.Template>
    <ControlTemplate TargetType="{x:Type ItemsControl}">
      <Border Background="#121B25"
              BorderBrush="#32485F"
              BorderThickness="1"
              Padding="12">
        <ItemsPresenter />
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
</ItemsControl>

ListBox chrome with the same item host contract

<Style x:Key="CompactListBoxStyle" TargetType="{x:Type ListBox}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBox}">
        <Border Background="#0F1720"
                BorderBrush="#2D465E"
                BorderThickness="1"
                Padding="6">
          <ItemsPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Notes and pitfalls

Do not treat it as a standalone control. Placing an ItemsPresenter in arbitrary XAML without an owning ItemsControl above it gives you an empty host.

One presenter usually means one active host. The owning items control attaches to the active items host, so templates should provide a single clear location where realized items belong.

Layout is always vertical here. If you expected wrapping, horizontal flow, or grid-style item placement, this implementation does not expose that through ItemsPresenter.

No virtualization guarantee. The presenter hosts the owner's realized visuals, and those realized children are still measured and arranged in order.