WPF Bootcamp

Collections and Item Controls

Most real applications render lists, menus, trees, grids, and grouped collections. WPF solves that with item controls that generate visuals from data rather than asking you to manually build repeated UI elements.

This is where collection change notifications, item templates, and selection patterns become essential.

What you'll learn

  • Why ObservableCollection<T> matters for live UIs.
  • How ItemsControl, ListBox, and related controls generate containers.
  • How item templates, selected item state, and collection views fit together.
  • How to reason clearly about data items, generated containers, and the control that owns the collection.
<ListBox ItemsSource="{Binding Documents}"
         SelectedItem="{Binding SelectedDocument}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

That small example already involves several cooperating systems: a bound collection, generated item containers, a data template, and selected-item synchronization back to the view model.

The mental model in one sentence

An items control owns a collection-shaped UI problem: it takes a source of items, generates containers, applies templates to each item, and often manages interaction state such as selection and focus.

Data item

The object from your collection, such as a document, customer, or message view model.

Generated container

The UI wrapper created by the control, such as ListBoxItem, which carries selection and control-specific behavior.

Why ObservableCollection<T> matters

A live UI needs to know when items are added or removed from a bound collection. A plain List<T> does not notify the UI about those collection-level changes.

public ObservableCollection<DocumentViewModel> Documents { get; } =
    new ObservableCollection<DocumentViewModel>();

When you add or remove items from an observable collection, item controls can refresh automatically. Without that notification, the UI may continue showing stale data until the entire binding is refreshed or reassigned.

Practical takeaway: if your list UI is not reacting to inserts or removals, check the collection type before you debug templates or selection behavior.

ItemsControl is the base pattern

ItemsControl is the fundamental abstraction for showing repeated items from a collection. More specialized controls such as ListBox, ComboBox, and TreeView build on that idea and add richer interaction behavior.

ItemsControl

Best when you only need repeated rendering and layout, not built-in selection or editing behavior.

ListBox

Adds selection, keyboard navigation, focus behavior, and item-container state.

Choosing the right control matters because the control family, not just the data template, determines what behavior the list supports.

Understand the generated pieces

Your data item is not the same thing as the item container. In a ListBox, each item is wrapped in a ListBoxItem. The container handles selection, focus, and chrome. The item template handles how the data looks.

  • Use the data item for business state.
  • Use the container for selection and interaction state.
  • Use collection views when you need sorting, grouping, or filtering without mutating the original list.
<ListBox ItemsSource="{Binding Documents}" />

The control does not simply drop your document objects into the visual tree. It creates a container per item, then uses the template layer to decide how each item's content should appear inside that container.

Item template vs item container style

This distinction is one of the biggest sources of confusion in list UIs.

Item template

Controls how the item's data is rendered. This is where you decide what visual tree represents each data object.

Container style

Controls the generated wrapper's behavior and appearance, such as selection visuals, margins, or focus-related chrome.

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Name}" />
    </DataTemplate>
</ListBox.ItemTemplate>

If the problem is "selected rows do not look right", the issue may be in the container style rather than the data template. If the problem is "the wrong fields are shown", the item template is the right place to inspect.

Selection belongs in the control and the view model

Selection is usually a first-class part of screen state. In MVVM, you normally bind it to the view model rather than reading it imperatively from the view.

<ListBox
    ItemsSource="{Binding Documents}"
    SelectedItem="{Binding SelectedDocument}" />

The control manages the interaction mechanics of selection. The view model owns the durable meaning of which item is currently selected.

This is much cleaner than asking the view for its selected item every time some other action needs it.

Collection views add sorting, grouping, and filtering

Sometimes you need a different view over the same underlying collection without mutating the original data structure. Collection views provide that layer.

  • Sort items without reordering the original source list permanently.
  • Filter what the control shows based on UI conditions.
  • Group items for richer presentation.

This lets the view stay responsive and flexible without forcing the view model or model layer to constantly rebuild collections just to satisfy one visual presentation need.

When to use an ItemsControl vs a panel

A panel like StackPanel is for explicitly authored children. An items control is for data-driven repetition.

<StackPanel>
    <TextBlock Text="File A" />
    <TextBlock Text="File B" />
</StackPanel>

<ListBox ItemsSource="{Binding Files}" />

Those can look superficially similar when rendered, but only the second one is a proper collection UI abstraction. It understands containers, selection, and dynamic collection changes.

A worked list-screen example

<ListBox
    ItemsSource="{Binding Documents}"
    SelectedItem="{Binding SelectedDocument}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding ModifiedAt}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
  1. The control binds to a collection of document view models.
  2. For each item, the control generates a ListBoxItem container.
  3. The data template defines the inner visuals for each document.
  4. When the user selects an item, the control updates its container state and the bound SelectedDocument property.
  5. If the collection is observable and a document is added or removed, the list updates without rebuilding the whole screen manually.

That is the core pattern for a large portion of WPF applications: data collection, generated containers, templates, and selected-item state all cooperating.

Common mistakes

  • Binding to a plain List<T> and expecting the UI to refresh when items are added or removed.
  • Styling the data template when the issue is actually on the generated item container.
  • Mutating selection state in the view instead of binding it to the view model.
  • Using a panel for data-driven repetition when an items control should own the collection behavior.
  • Confusing the data item with the generated container and debugging the wrong layer.

InkkSlinger parity note: The repository includes WPF-style items controls and collection-view infrastructure under `UI/Binding/Collections` and `UI/Controls/Items`. The same collection-notification and item-generation ideas apply directly.

Next, learn styling and templating so the same data and controls can support multiple visual languages without rewriting behavior.