Controls that inherit from ItemsControl contain a collection of objects. An example of an ItemsControl is the ListBox. You can use either the ItemsSource property or the Items property to populate an ItemsControl.
ItemsSource Property
The ItemsSource property of the ItemsControl enables you to use any type that implements IEnumerable as the content of the ItemsControl. ItemsSource is typically used to display a data collection or to bind an ItemsControl to a collection object.
The following example creates a class called MyData that is a simple string collection.
public class MyData : ObservableCollection<string>
{
public MyData()
{
Add("Item 1");
Add("Item 2");
Add("Item 3");
}
}
Public Class MyData
Inherits ObservableCollection(Of String)
Public Sub New() '
Add("Item 1")
Add("Item 2")
Add("Item 3")
End Sub 'New
End Class 'MyData
The following example binds ItemsSource to MyData.
<!--Create an instance of MyData as a resource.-->
<src:MyData x:Key="dataList"/>
...
<ListBox ItemsSource="{Binding Source={StaticResource dataList}}"/>
ListBox listBox1 = new ListBox();
MyData listData = new MyData();
Binding binding1 = new Binding();
binding1.Source = listData;
listBox1.SetBinding(ListBox.ItemsSourceProperty, binding1);
Dim listBox1 As New ListBox()
Dim listData As New MyData()
Dim binding1 As New Binding()
binding1.Source = listData
listBox1.SetBinding(ListBox.ItemsSourceProperty, binding1)
The following figure shows the ListBox created in the previous example.
For more information about data binding, see Data Binding Overview.
Items Property
If you do not want to use an object that implements IEnumerable to populate the ItemsControl, you can add items by using the Items property. The items in an ItemsControl can have types that are different from each other. For example, a ListBox can contain one item that is a string and another item that is an Image.
The following example creates a ListBox with four different types of items.
<!--Create a ListBox that contains a string, a Rectangle,
a Panel, and a DateTime object. These items can be accessed
via the Items property.-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="simpleListBox">
<!-- The <ListBox.Items> element is implicitly used.-->
This is a string in a ListBox
<sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
<Rectangle Height="40" Width="40" Fill="Blue"/>
<StackPanel Name="itemToSelect">
<Ellipse Height="40" Fill="Blue"/>
<TextBlock>Text below an Ellipse</TextBlock>
</StackPanel>
<TextBlock>String in a TextBlock</TextBlock>
<!--</ListBox.Items>-->
</ListBox>
// Add a String to the ListBox.
listBox1.Items.Add("This is a string in a ListBox");
// Add a DateTime object to a ListBox.
DateTime dateTime1 = new DateTime(2004, 3, 4, 13, 6, 55);
listBox1.Items.Add(dateTime1);
// Add a Rectangle to the ListBox.
Rectangle rect1 = new Rectangle();
rect1.Width = 40;
rect1.Height = 40;
rect1.Fill = Brushes.Blue;
listBox1.Items.Add(rect1);
// Add a panel that contains multpile objects to the ListBox.
Ellipse ellipse1 = new Ellipse();
TextBlock textBlock1 = new TextBlock();
ellipse1.Width = 40;
ellipse1.Height = 40;
ellipse1.Fill = Brushes.Blue;
textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.Text = "Text below an Ellipse";
stackPanel1.Children.Add(ellipse1);
stackPanel1.Children.Add(textBlock1);
listBox1.Items.Add(stackPanel1);
' Create a Button with a string as its content.
listBox1.Items.Add("This is a string in a ListBox")
' Create a Button with a DateTime object as its content.
Dim dateTime1 As New DateTime(2004, 3, 4, 13, 6, 55)
listBox1.Items.Add(dateTime1)
' Create a Button with a single UIElement as its content.
Dim rect1 As New Rectangle()
rect1.Width = 40
rect1.Height = 40
rect1.Fill = Brushes.Blue
listBox1.Items.Add(rect1)
' Create a Button with a panel that contains multiple objects
' as its content.
Dim ellipse1 As New Ellipse()
Dim textBlock1 As New TextBlock()
ellipse1.Width = 40
ellipse1.Height = 40
ellipse1.Fill = Brushes.Blue
textBlock1.TextAlignment = TextAlignment.Center
textBlock1.Text = "Text below an Ellipse"
stackPanel1.Children.Add(ellipse1)
stackPanel1.Children.Add(textBlock1)
listBox1.Items.Add(stackPanel1)
The following figure shows the ListBox created in the previous example.
Item Container Classes
Each ItemsControl that ships with WPF has a corresponding class that represents an item in the ItemsControl. The following table lists the ItemsControl objects that ship with WPF and their corresponding item containers.
You can explicitly create an item container for each item in the ItemsControl, but it is not necessary. Whether you to create an item container in your ItemsControl depends largely on your scenario. For example, if you bind data to the ItemsSource property, you will not explicitly create an item container. The following points are important to keep in mind:
-
The type of the objects in the ItemCollection differs depending on whether you explicitly create an item container.
-
You can get the item container even if you do not explicitly create it.
-
A Style with the TargetType set to an item container is applied regardless of whether the item container is explicitly created.
-
Property inheritance behaves differently for implicitly and explicitly created item containers because only explicitly created item containers are part of the logical tree.
To illustrate these points, the following example creates the two ListBox controls. The example creates ListBoxItem objects for the first ListBox, but not the second ListBox. In the second case, a ListBoxItem is implicitly created for each item in the ListBox.
<!--Explicitly create a ListBoxItem for each item in the ListBox-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="listBoxItemListBox">
<!-- The <ListBox.Items> element is implicitly used.-->
<ListBoxItem>
This is a string in a ListBox
</ListBoxItem>
<ListBoxItem>
<sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
</ListBoxItem>
<ListBoxItem>
<Rectangle Height="40" Width="40" Fill="Blue"/>
</ListBoxItem>
<ListBoxItem>
<StackPanel>
<Ellipse Height="40" Width="40" Fill="Blue"/>
<TextBlock>Text below an Ellipse</TextBlock>
</StackPanel>
</ListBoxItem>
<!--</ListBox.Items>-->
</ListBox>
...
<!--Create a ListBox that contains a string, a Rectangle,
a Panel, and a DateTime object. These items can be accessed
via the Items property.-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="simpleListBox">
<!-- The <ListBox.Items> element is implicitly used.-->
This is a string in a ListBox
<sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
<Rectangle Height="40" Width="40" Fill="Blue"/>
<StackPanel Name="itemToSelect">
<Ellipse Height="40" Fill="Blue"/>
<TextBlock>Text below an Ellipse</TextBlock>
</StackPanel>
<TextBlock>String in a TextBlock</TextBlock>
<!--</ListBox.Items>-->
</ListBox>
The ItemCollection for each ListBox is different. Each item in the Items property of the first ListBox is a ListBoxItem, but is a different type in the second ListBox. The following example confirms this by iterating through the items in both ListBox controls and checking the type of each item.
Console.WriteLine("Items in simpleListBox:");
foreach (object item in simpleListBox.Items)
{
Console.WriteLine(item.GetType().ToString());
}
Console.WriteLine("\rItems in listBoxItemListBox:");
foreach (object item in listBoxItemListBox.Items)
{
Console.WriteLine(item.GetType().ToString());
}
...
/*
Items in simpleListBox:
System.String
System.Windows.Shapes.Rectangle
System.Windows.Controls.StackPanel
System.DateTime
Items in listBoxItemListBox:
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
*/
Console.WriteLine("Items in simpleListBox:")
For Each item As Object In simpleListBox.Items
Console.WriteLine(item.GetType().ToString())
Next item
Console.WriteLine(vbCr + "Items in listBoxItemListBox:")
For Each item As Object In listBoxItemListBox.Items
Console.WriteLine(item.GetType().ToString())
Next item
End Sub 'ReportLBIs
...
'
' Items in simpleListBox:
' System.String
' System.Windows.Shapes.Rectangle
' System.Windows.Controls.StackPanel
' System.DateTime
'
' Items in listBoxItemListBox:
' System.Windows.Controls.ListBoxItem
' System.Windows.Controls.ListBoxItem
' System.Windows.Controls.ListBoxItem
' System.Windows.Controls.ListBoxItem
'
The following figure shows the two ListBox controls that were created in the previous example.
Often, you will want the item container for an item. but you have not explicitly created it in your application. To get the item container that is associated with a particular item, use the ContainerFromItem method. The following example shows how to get an item container associated with an item when a ListBoxItem is not explicitly created. The example assumes that the object called itemToSelect is not a ListBoxItem and has been added to the ListBox, simpleListBox.
ListBoxItem lbi =
simpleListBox.ItemContainerGenerator.ContainerFromItem(itemToSelect)
as ListBoxItem;
if (lbi != null)
{
lbi.IsSelected = true;
}
Dim lbi As ListBoxItem = _
CType(simpleListBox.ItemContainerGenerator.ContainerFromItem(itemToSelect), _
ListBoxItem)
If Not (lbi Is Nothing) Then
lbi.IsSelected = True
End If
Styles that have the TargetType set to an item container are applied to both implicitly and explicitly created item containers. The following example creates a Style as a resource for a ListBoxItem that horizontally centers the contents in the ListBoxItem. When this style is applied to the ListBox objects, the items in both of the ListBox objects are centered.
<!--Create a Style as a Resource.-->
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
The following figure shows the two ListBox controls when the style in the previous example is applied.
How property inheritance works with styles and item containers is related to how the logical tree is structured. When you explicitly create the item container, it is part of the logical tree. If you do not create the item container, it is not part of the logical tree. The following figure shows the difference in the logical tree for the two ListBox controls in the previous example.
Objects that inherit from the Visual class inherit property values from their logical parent. The following example creates a ListBox with two TextBlock controls and sets the Foreground property of the ListBox to blue. The first TextBlock, textBlock1, is contained within an explicitly created ListBoxItem and the second TextBlock, textBlock2, is not. The example also defines a Style for a ListBoxItem that sets the Foreground of a