This is the first post in a series I’m calling, “ItemsControl: A to Z”.
I’ve received quite a few questions lately that were either directly or indirectly related to the ItemsControl class. It’s noteworthy that often, the questioner did not even realize they were asking an ItemsControl question.
So it occurs to me that there may be a general need for better information about this class, including its usages, nuances, idiosyncrasies, as well as all the WPF goodness that can be had through styling and templating an ItemsControl and binding a collection to it.
(And let me just say up front that it’s highly unlikely I’ll make it all the way to Z without skipping a few letters. J)
But first things first… I suppose we should start with the basics.
What is an ItemsControl?
Quite simply, an ItemsControl is a control that presents a collection of items.
The ItemsControl is one of the most abundant controls in the user interface of just about any WPF application. It is the base class of every native WPF control that presents a collection of items, including but not limited to the following:
|
ComboBox
|
 |
<ComboBox SelectedIndex="0">
<ComboBoxItem>Item 1</ComboBoxItem>
<ComboBoxItem>Item 2</ComboBoxItem>
<ComboBoxItem>Item 3</ComboBoxItem>
</ComboBox>
|
ContextMenu
Menu
MenuItem
|
|
<ContextMenu>
<MenuItem Header="New"/>
<MenuItem Header="Open"/>
<Separator/>
<MenuItem Header="Submenu">
<MenuItem Header="Submenu Item 1"/>
<MenuItem Header="Submenu Item 2"/>
</MenuItem>
</ContextMenu>
|
ListBox
|
 |
<ListBox SelectedIndex="0" Width="100">
<ListBoxItem>Item 1</ListBoxItem>
<ListBoxItem>Item 2</ListBoxItem>
<ListBoxItem>Item 3</ListBoxItem>
<ListBoxItem>Item 4</ListBoxItem>
<ListBoxItem>Item 5</ListBoxItem>
</ListBox>
|
ListView
|
 |
<ListView SelectedIndex="0" Height="110"
ItemsSource="{StaticResource Characters}">
<ListView.View>
<GridView>
<GridViewColumn Width="100"
DisplayMemberBinding="{Binding Last}"
Header="Last Name" />
<GridViewColumn Width="100"
DisplayMemberBinding="{Binding First}"
Header="First Name" />
<GridViewColumn Width="60"
DisplayMemberBinding="{Binding Gender}"
Header="Gender" />
</GridView>
</ListView.View>
</ListView>
|
TabControl
|
 |
<TabControl Width="150" Height="100">
<TabItem Header="One">
<TextBlock>Hello World</TextBlock>
</TabItem>
<TabItem Header="Two" />
<TabItem Header="Three" />
</TabControl>
|
ToolBar
|
 |
<ToolBar Margin="2">
<Button Command="ApplicationCommands.Open"
Height="40" Width="40"
Background="{StaticResource OpenIcon}" />
<Button Command="ApplicationCommands.Save"
Height="40" Width="40"
Background="{StaticResource SaveIcon}" />
</ToolBar>
|
TreeView
TreeViewItem
|
|
<TreeView Width="150" Height="100"
ItemsSource="{StaticResource Characters}">
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type src:Character}"
ItemsSource ="{Binding Fact}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type src:Fact}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text=": " />
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
A Control in its Own Right
The controls listed above are most often used because of the additional features they provide on top of the base ItemsControl class. However, it should also be noted that an ItemsControl may be instantiated and used directly, as shown in the following example:
<Grid xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ItemsControl VerticalAlignment="Top">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding}" Content="{Binding}"
CommandTarget="{Binding ElementName=EditRegion}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<x:Static Member="ApplicationCommands.Cut" />
<x:Static Member="ApplicationCommands.Copy" />
<x:Static Member="ApplicationCommands.Paste" />
</ItemsControl>
<TextBox Name="EditRegion" Grid.Row="1" />
</Grid>
This markup creates what you might call a poor man’s toolbar. (No, it’s not a very likely real-world scenario.) In future posts, we will explore reasons why you might choose to use an ItemsControl directly, rather than, say, a ListBox.
Is a Panel an ItemsControl?
No. The logical children of a panel are UIElements, whereas the logical children of an ItemsControl (its Items) can be any CLR objects.
Sidebar: So what is a panel? The main role of a panel is to provide layout support for its children. Although a panel does maintain a collection of child elements, it is not technically a WPF “control”… That is, it does not derive from the Control base class and it does not support the WPF notion of templating. Instead, it is a single element with a single purpose… namely, to size and position (a.k.a., measure and arrange) its children.
Why should I care about the ItemsControl class?
Since it’s such an abundant control, it will pay dividends to take time now to understand the basic principles that apply to the ItemsControl class and its descendants. Once you understand these concepts as they pertain to one ItemsControl variant, perhaps a ListBox, it will be very easy to apply that same knowledge to other variants.
And suppose you should someday stumble upon a declaration like this:
<dw:Graph ItemsSource="{Binding Source={StaticResource OrgChartItems}}"
ItemContainerStyle="{StaticResource NodeStyle}"
ItemTemplate="{StaticResource EmployeeTemplate}"
ItemsPanel="{StaticResource TreeGraphPanelTemplate}" />
Armed with your existing knowledge, you won’t panic in the least. You will simply recognize that this Graph object is a custom ItemsControl and you will immediately understand how to use the majority of its features.
What will be covered?
In future posts in this series, I hope to cover each of the topics below in some detail. I’m sure this is not an exhaustive list, but it should give you a general feel for the direction of the series.
-
The Item Collection: Items vs. ItemsSource
-
Recognizing when to use an ItemsControl
-
Item Templates
-
Item Containers
-
Item Container Generation
-
The Items Host (or ItemsPanel)
-
Styling and Templating an ItemsControl
-
Traversing Container and Template Trees
-
The HeaderedItemsControl
-
Styling and Templating a Headered ItemsControl
-
Building a Custom ItemsControl and Item Containers
-
UI Virtualization
Please let me know what other topics you’d like me to add to the list. And please stay tuned for the next topic in this series… "B is for Bet You Can’t Find Them All!"