Introduction
ItemsControl is a control within the Windows Presentation Foundation (WPF) framework that facilitates the display of a collection of items, which may include data objects or user interface elements. It acts as a foundational class for various other item-oriented controls, such as ListBox, ListView, ComboBox, TreeView, and Menu. Notably, ItemsControl is a more versatile control that does not inherently include specific features for selection, scrolling, or other interactions. Rather, it offers a customizable approach to organizing items through tailored layouts and templates.
Key Properties
- ItemsSource: Establishes a connection between the control and a collection of items, which may consist of strings, objects, or any other data source.
- ItemTemplate: Determines the visual representation of each item within the collection by utilizing a DataTemplate. For instance, when dealing with custom objects, ItemTemplate can be employed to specify how their properties should be visually represented.
- ItemTemplateSelector: Allows for the selection of distinct templates for individual items based on specific criteria. This feature is particularly beneficial when items possess varying layouts or types of content.
- ItemsPanel: Specifies the layout panel responsible for organizing the items. Options include using a StackPanel, WrapPanel, or a custom panel to manage the arrangement of items within the ItemsControl.
Key Characteristics of ItemsControl
- Versatile Layout: ItemsControl allows for the specification of various layout containers (ItemsPanel), enabling adaptability to different arrangements such as grids, stacks, or bespoke configurations.
- Tailored Presentation: Utilizing ItemTemplate and ItemTemplateSelector, you can manage the representation of each item according to its associated data.
- Foundation for Specialized Controls: Controls such as ListBox and TreeView derive from ItemsControl, incorporating additional specialized functionalities like item selection and hierarchical organization. ItemsControl is a control within the Windows Presentation Foundation (WPF) framework that facilitates the display of a collection of items, which may include data objects or user interface elements. It acts as a foundational class for various other item-oriented controls, such as ListBox, ListView, ComboBox, TreeView, and Menu. Notably, ItemsControl is a more versatile control that does not inherently include specific features for selection, scrolling, or other interactions. Rather, it offers a customizable approach to organizing items through tailored layouts and templates.
Implementation of ItemsControl
Step 1. Create a Model Class like the one below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TemplateExample
{
public class DataModel
{
public string Label { get; set; }
public string PropertyType { get; set; } // This will help us select the template
public string Input { get; set; }
}
}
Step 2. Create a ViewModel like the one below.
using System.Collections.ObjectModel;
namespace TemplateExample
{
internal class MainWindowViewModel
{
public ObservableCollection<DataModel> ItemsTemplateSourceDataList { get; set; }
public MainWindowViewModel()
{
ItemsTemplateSourceDataList = new ObservableCollection<DataModel>
{
new DataModel { Label = "Name", PropertyType = "Text" },
new DataModel { Label = "Email", PropertyType = "Email" },
new DataModel { Label = "Phone", PropertyType = "Phone" },
new DataModel { Label = "Address", PropertyType = "Text" },
new DataModel { Label = "Comments", PropertyType = "Comments" },
new DataModel { Label = "Additional Information", PropertyType = "Text" },
new DataModel { Label = "Feedback", PropertyType = "Comments" }
};
}
}
}
Step 3. Create a template selector like below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
namespace TemplateExample
{
public class PropertyTemplateSelector : DataTemplateSelector
{
public DataTemplate TextTemplate { get; set; }
public DataTemplate EmailTemplate { get; set; }
public DataTemplate PhoneTemplate { get; set; }
public DataTemplate CommentsTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is DataModel DataModel)
{
switch (DataModel.PropertyType)
{
case "Text":
return TextTemplate;
case "Email":
return EmailTemplate;
case "Phone":
return PhoneTemplate;
case "Comments":
return CommentsTemplate;
default:
return base.SelectTemplate(item, container);
}
}
return base.SelectTemplate(item, container);
}
}
}
Step 4. Define the DataTemplate in XAML.
<Window x:Class="TemplateExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TemplateExample"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<!-- Template for Text Property -->
<DataTemplate x:Key="TextTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelGroup" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Label}" FontSize="14" Margin="5" Grid.Column="0" Grid.Row="0" />
<GridSplitter Width="5" Background="DarkGray" HorizontalAlignment="Stretch" Grid.Column="1" ResizeDirection="Columns" Grid.Row="0" />
<TextBox Text="{Binding Input}" Margin="5" Grid.Column="2" HorizontalAlignment="Stretch" Grid.Row="0" />
</Grid>
</DataTemplate>
<!-- Template for Email Property -->
<DataTemplate x:Key="EmailTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelGroup" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" FontSize="14" Margin="5" Grid.Column="0" />
<GridSplitter Width="5" Background="DarkGray" HorizontalAlignment="Stretch" Grid.Column="1" ResizeDirection="Columns" />
<TextBox Text="{Binding Input}" Margin="5" Grid.Column="2" HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
<!-- Template for Phone Property -->
<DataTemplate x:Key="PhoneTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelGroup" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" FontSize="14" Margin="5" Grid.Column="0" />
<GridSplitter Width="5" Background="DarkGray" HorizontalAlignment="Stretch" Grid.Column="1" ResizeDirection="Columns" />
<TextBox Text="{Binding Input}" Margin="5" Grid.Column="2" HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
<!-- Template for Comments (Multi-line Text) Property -->
<DataTemplate x:Key="CommentsTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelGroup" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" FontSize="14" Margin="5" Grid.Column="0" />
<GridSplitter Width="5" Background="DarkGray" HorizontalAlignment="Stretch" Grid.Column="1" ResizeDirection="Columns" />
<TextBox Text="{Binding Input}" Margin="5" Grid.Column="2" AcceptsReturn="True" Height="100" HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
<!-- DataTemplateSelector for Choosing Template Based on PropertyType -->
<local:PropertyTemplateSelector x:Key="SettingTemplateSelector"
TextTemplate="{StaticResource TextTemplate}"
EmailTemplate="{StaticResource EmailTemplate}"
PhoneTemplate="{StaticResource PhoneTemplate}"
CommentsTemplate="{StaticResource CommentsTemplate}" />
</Window.Resources>
<!-- ItemsControl with ScrollViewer -->
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid IsSharedSizeScope="True" HorizontalAlignment="Stretch">
<ItemsControl x:Name="SettingsItemsPanel"
ItemsSource="{Binding ItemsTemplateSourceDataList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemTemplateSelector="{StaticResource SettingTemplateSelector}">
</ItemsControl>
</Grid>
</ScrollViewer>
</Window>
Step 5. Set the Window’s DataContext (in Code-Behind).
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace TemplateExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
}
Step 6. The output will appear as follows.
Элементы управления списками
Последнее обновление: 28.01.2023
Эти элементы представлены в WPF довольно широко. Все они являются производными от класса ItemsControl,
который в свою очередь является наследником класса Control. Все они содержат коллекцию элементов. Элементы могут быть напрямую добавлены в коллекцию,
возможна также привязка некоторого массива данных к коллекции.
Возьмем простейший элемент-список — ListBox и определим в файле MainWindow.xaml следующий интерфейс:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:MetanitApp" mc:Ignorable="d" Name="MainWindow" Height="200" Width="300"> <ListBox x:Name="usersList"> <sys:String>Tom</sys:String> <sys:String>Bob</sys:String> <sys:String>Sam</sys:String> <sys:String>Alice</sys:String> </ListBox> </Window>
Все элементы, размещенные внутри спискового элемента ListBox, представляют элементы списка.
Управление списком
Коллекция объектов внутри элемента-списка доступна в виде свойства Items. Для управления элементами из этой коллекции мы можем использовать следующие методы:
- Add(object item): добавление элемента
- Clear(): полная очистка коллекции
- Insert(int index, object item): вставка элемента по определенному индексу в коллекции
- Remove(object item): удаление элемента
- RemoveAt(int index): удаление элемента по индексу
А свойство Count позволяет узнать, сколько элементов в коллекции.
Например, оставим предыдущий интерфейс и в файле связанного кода MainWindow.xaml.cs добавим и удалим программно несколько элементов:
using System.Windows; namespace MetanitApp { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); usersList.Items.Remove("Sam"); // удаляем элемент "Sam" usersList.Items.RemoveAt(1); // удаляем второй элемент usersList.Items.Add("Kate"); // Добавляем элемент "Kate" usersList.Items.Insert(0, "Mike"); // Вставляем элемент "Mike" на первое место в списке } } }
В данном случае добавляем и удаляем ряд элементов с помощью различных методов и в итоге получим следующий список:
При вызове методов, которые используют индексы, как выше методы RemoveAt(index)
и Insert(index, object)
, следует учитывать, что передаваемые индексы
должны быть действительны. Естественно мы не можем удалить, к примеру, второй объект, если списке только один объект или вообще нет объектов. В этом случае мы можем проверять
длину списка:
if(usersList.Items.Count > 1) // если в списке больше 1 элемента { usersList.Items.Insert(1, "Mike"); // Вставляем элемент "Mike" на второе место usersList.Items.RemoveAt(2); // удаляем третий элемент }
Отображение сложных данных
Списковые элементы могут отображать не только простые строки или числа, но и сложные данные. Например, создадим в коде новый класс Person:
public class Person { public string Name { get; set; } = ""; public int Age { get; set; } public override string ToString() { return $"Name: {Name} Age: {Age}"; } }
Теперь создадим в xaml набор объектов этого класса Person и выведем в их в списке:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:MetanitApp" mc:Ignorable="d" Title="MainWindow" Height="200" Width="300"> <ListBox x:Name="usersList"> <local:Person Name="Tom" Age="38" /> <local:Person Name="Bob" Age="42" /> <local:Person Name="Sam" Age="25" /> <local:Person Name="Alice" Age="34" /> </ListBox> </Window>
Поскольку мы используем класс, определенный в текущем проекте, то соответственно у нас обязательно должно быть подключено пространство имен проекте.
В моем случае проект (и пространство имен) называется «MetanitApp». Соответственно у меня это пространство имен проецируется на префикс local:
xmlns:local="clr-namespace:MetanitApp"
В принципе по умолчанию WPF уже его подключает. После этого через префикс «local» можно обращаться к классу Person: «local:Person».
Кроме того, чтобы не возникало проблем с разметкой XAML, желательно сделать перестроение проекта. И в итоге ListBox выведет все объекты:
По умолчанию списковые элементы выводят то, что возвращает метод ToString()
объекта. Именно для этой демонстрации и реализован данный метод в классе Person выше.
Но также с помощью свойства DisplayMemberPath можно установить свойство объекта, значение которого будет отображаться в списке. Например, отобразим только имя:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MetanitApp" mc:Ignorable="d" Title="MainWindow" Height="200" Width="300"> <ListBox x:Name="usersList" DisplayMemberPath="Name"> <local:Person Name="Tom" Age="38" /> <local:Person Name="Bob" Age="42" /> <local:Person Name="Sam" Age="25" /> <local:Person Name="Alice" Age="34" /> </ListBox> </Window>
В этом случае в коде C# таким же образом можно добавлять и удалять данные:
var firstPerson = usersList.Items[0]; // получаем первый объект usersList.Items.Remove(firstPerson); // удаляем его usersList.Items.Add(new Person { Name = "Kate", Age = 23 }); // добавляем новый объект
ItemsSource
Нам необязательно вручную заполнять значения элемента управления списком, так как мы можем установить свойство ItemsSource,
задав в качестве параметра коллекцию, из которой будет формироваться элемент управления списком. Например, в коде xaml-разметки определим пустой список:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="MainWindow" Height="200" Width="300"> <ListBox x:Name="usersList" /> </Window>
А в файле отделенного кода выполним наполнение списка:
using System.Windows; using System.Collections.Generic; namespace MetanitApp; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); usersList.ItemsSource = new List<Person>() { new Person{Name="Tom", Age=38}, new Person {Name="Bob", Age=42}, new Person{Name="Sam", Age=25} }; // устанавливаем отображаемое свойство usersList.DisplayMemberPath = "Name"; } }
Но стоит учитывать, что если мы наполняем элемент управления списком через свойство ItemsSource, то мы не сможем использовать
выше рассмотренные методы Add/Remove/RemoveAt/Insert/Clear
для добавления/удаления элементов списка. В этом случае для управления элементами непосредственно к самому источнику данных.
Например, определим в коде xaml кнопку для добавления одного объекта:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="MainWindow" Height="200" Width="300"> <StackPanel> <ListBox x:Name="usersList" DisplayMemberPath="Name" /> <Button Content="Add" Click="Button_Click" Margin="5" Width="80" HorizontalAlignment="Left" /> </StackPanel> </Window>
По нажатию на кнопку будет вызываться метод Button_Click
. И в файле связанного кода C# определим данный метод и наполним ListBox данными:
using System.Windows; using System.Collections.Generic; namespace MetanitApp; public partial class MainWindow : Window { List<Person> people = new List<Person>() { new Person{Name="Tom", Age=38}, new Person {Name="Bob", Age=42}, new Person{Name="Sam", Age=25} }; public MainWindow() { InitializeComponent(); usersList.ItemsSource = people; } private void Button_Click(object sender, RoutedEventArgs e) { people.Add(new Person { Name = "Mike", Age = 29 }); usersList.Items.Refresh(); } }
Здесь в качестве источника данных выступает список people, и из этого списка ListBox будет брать данные.
В обработчике нажатия кнопки добавляем в список people один объект Person для теста. Обратите внимание, что добавляем именно в стандартный список List<Person>
,
а не в ListBox. ListBox в данном случае просто отображает данные. Но чтобы ListBox обновил свое визуальное представление, после изменения списка people обновляем данные в ListBox:
usersList.Items.Refresh();
Стоит отметить, что если в качестве источника данных выступает ObservableCollection
, то нам не надо вызывает отобновление данных списка, так как коллекция ObservableCollection сама извещает систему
об изменениях.
Выбор элементов
Все элементы управления списками поддерживают выделение входящих элементов. Выделенный элемент(ы) можно получить с помощью свойств
SelectedItem(SelectedItems), а получить индекс выделенного элемента — с помощью свойства SelectedIndex.
Свойство SelectedValue позволяет получить значение выделенного элемента.
При выделении элемента в списке генерируется событие SelectionChanged, которое мы можем обработать. Например, возьмем предыдущий список:
<Window x:Class="MetanitApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MetanitApp" mc:Ignorable="d" Title="MainWindow" Height="200" Width="300"> <ListBox x:Name="usersList" DisplayMemberPath="Name" SelectionChanged="usersList_SelectionChanged"> <local:Person Name="Tom" Age="38" /> <local:Person Name="Bob" Age="42" /> <local:Person Name="Sam" Age="25" /> <local:Person Name="Alice" Age="34" /> </ListBox> </Window>
А в файле кода определим обработчик для этого события:
using System.Windows; using System.Windows.Controls; namespace MetanitApp; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void usersList_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (usersList.SelectedItem is Person person) { MessageBox.Show(person.Name); } } }
Важно учитывать, что так как в разметке xaml в списке определены элементы Person, то в коде мы можем привести объект usersList.SelectedItem
к типу Person.
Represents a control that can be used to present a collection of items.
Inheritance
System.Object
ItemsControl
Inherited Members
System.Object.Equals(System.Object)
System.Object.Equals(System.Object, System.Object)
System.Object.GetHashCode()
System.Object.GetType()
System.Object.MemberwiseClone()
System.Object.ReferenceEquals(System.Object, System.Object)
System.Object.ToString()
Namespace: System.Windows.Controls
Assembly: OpenSilver.dll
Syntax
public class ItemsControl : Control, IControl, IFrameworkElement, IUIElement, IDependencyObject
Constructors
|
Improve this Doc
View Source
ItemsControl()
Initializes a new instance of the ItemsControl class.
Declaration
Fields
|
Improve this Doc
View Source
DisplayMemberPathProperty
Identifies the DisplayMemberPath dependency property.
Declaration
public static readonly DependencyProperty DisplayMemberPathProperty
Field Value
Type | Description |
---|---|
DependencyProperty |
|
Improve this Doc
View Source
ItemContainerStyleProperty
Identifies the ItemContainerStyle dependency property.
Declaration
public static readonly DependencyProperty ItemContainerStyleProperty
Field Value
Type | Description |
---|---|
DependencyProperty |
|
Improve this Doc
View Source
ItemsPanelProperty
Identifies the ItemsPanel dependency property.
Declaration
public static readonly DependencyProperty ItemsPanelProperty
Field Value
Type | Description |
---|---|
DependencyProperty |
|
Improve this Doc
View Source
ItemsSourceProperty
Identifies the ItemsSource dependency property.
Declaration
public static readonly DependencyProperty ItemsSourceProperty
Field Value
Type | Description |
---|---|
DependencyProperty |
|
Improve this Doc
View Source
ItemTemplateProperty
Identifies the ItemTemplate dependency property.
Declaration
public static readonly DependencyProperty ItemTemplateProperty
Field Value
Type | Description |
---|---|
DependencyProperty |
Properties
|
Improve this Doc
View Source
DisplayMemberPath
Gets or sets a path to a value on the source object to serve as the visual
representation of the object.
Declaration
public string DisplayMemberPath { get; set; }
Property Value
Type | Description |
---|---|
System.String |
|
Improve this Doc
View Source
ItemContainerGenerator
Gets the ItemContainerGenerator associated with this ItemsControl.
Declaration
public ItemContainerGenerator ItemContainerGenerator { get; }
Property Value
Type | Description |
---|---|
ItemContainerGenerator |
|
Improve this Doc
View Source
ItemContainerStyle
Gets or sets the style that is used when rendering the item containers.
Declaration
public Style ItemContainerStyle { get; set; }
Property Value
Type | Description |
---|---|
Style |
|
Improve this Doc
View Source
Items
Items is the collection of data that is used to generate the content
of this control.
Declaration
public ItemCollection Items { get; }
Property Value
Type | Description |
---|---|
ItemCollection |
|
Improve this Doc
View Source
ItemsPanel
Gets or sets the template that defines the panel that controls the layout
of items.
Declaration
public ItemsPanelTemplate ItemsPanel { get; set; }
Property Value
Type | Description |
---|---|
ItemsPanelTemplate |
|
Improve this Doc
View Source
ItemsSource
Gets or sets an object source used to generate the content of the ItemsControl.
Declaration
public IEnumerable ItemsSource { get; set; }
Property Value
Type | Description |
---|---|
System.Collections.IEnumerable |
|
Improve this Doc
View Source
ItemTemplate
Gets or sets the DataTemplate used to display each item.
Declaration
public DataTemplate ItemTemplate { get; set; }
Property Value
Type | Description |
---|---|
DataTemplate |
|
Improve this Doc
View Source
LogicalChildren
Gets an enumerator for the logical child objects of the ItemsControl object.
Declaration
protected override IEnumerator LogicalChildren { get; }
Property Value
Type | Description |
---|---|
System.Collections.IEnumerator |
An enumerator for the logical child objects of the ItemsControl object. |
Overrides
Methods
|
Improve this Doc
View Source
ClearContainerForItemOverride(DependencyObject, Object)
Undoes the effects of the PrepareContainerForItemOverride method.
Declaration
protected virtual void ClearContainerForItemOverride(DependencyObject element, object item)
Parameters
Type | Name | Description |
---|---|---|
DependencyObject | element |
The container element. |
System.Object | item |
The item. |
|
Improve this Doc
View Source
GetContainerForItemOverride()
Creates or identifies the element that is used to display the given item.
Declaration
protected virtual DependencyObject GetContainerForItemOverride()
Returns
Type | Description |
---|---|
DependencyObject |
The element that is used to display the given item. |
|
Improve this Doc
View Source
GetItemsOwner(DependencyObject)
Declaration
public static ItemsControl GetItemsOwner(DependencyObject element)
Parameters
Type | Name | Description |
---|---|---|
DependencyObject | element |
Returns
Type | Description |
---|---|
ItemsControl |
|
Improve this Doc
View Source
IsItemItsOwnContainerOverride(Object)
Determines whether the specified item is (or is eligible to be) its
own container.
Declaration
protected virtual bool IsItemItsOwnContainerOverride(object item)
Parameters
Type | Name | Description |
---|---|---|
System.Object | item |
The item to check. |
Returns
Type | Description |
---|---|
System.Boolean |
True if the item is (or is eligible to be) its own container; otherwise, |
|
Improve this Doc
View Source
ItemsControlFromItemContainer(DependencyObject)
Declaration
public static ItemsControl ItemsControlFromItemContainer(DependencyObject container)
Parameters
Type | Name | Description |
---|---|---|
DependencyObject | container |
Returns
Type | Description |
---|---|
ItemsControl |
|
Improve this Doc
View Source
OnItemsChanged(NotifyCollectionChangedEventArgs)
Called when the value of the Items property changes.
Declaration
protected virtual void OnItemsChanged(NotifyCollectionChangedEventArgs e)
Parameters
Type | Name | Description |
---|---|---|
System.Collections.Specialized.NotifyCollectionChangedEventArgs | e |
A System.Collections.Specialized.NotifyCollectionChangedEventArgs that contains the event data |
|
Improve this Doc
View Source
OnItemsSourceChanged(IEnumerable, IEnumerable)
Declaration
protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
Parameters
Type | Name | Description |
---|---|---|
System.Collections.IEnumerable | oldValue | |
System.Collections.IEnumerable | newValue |
|
Improve this Doc
View Source
OnTextInput(TextCompositionEventArgs)
Declaration
protected override void OnTextInput(TextCompositionEventArgs e)
Parameters
Type | Name | Description |
---|---|---|
TextCompositionEventArgs | e |
Overrides
|
Improve this Doc
View Source
PrepareContainerForItemOverride(DependencyObject, Object)
Prepares the specified element to display the specified item.
Declaration
protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item)
Parameters
Type | Name | Description |
---|---|---|
DependencyObject | element |
The element that’s used to display the specified item. |
System.Object | item |
The item to display. |
|
Improve this Doc
View Source
UpdateItemsPanel(ItemsPanelTemplate)
Declaration
protected virtual void UpdateItemsPanel(ItemsPanelTemplate newTemplate)
Parameters
Type | Name | Description |
---|---|---|
ItemsPanelTemplate | newTemplate |
Extension Methods
ItemsControl
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.Control System.Windows.Controls.ItemsControl
ItemsControl
is the base class
for all controls that present lists or trees of items, including
ListBox
, TreeView
, and Menu
. Because it is a concrete class, it can
also be used in its own right. ItemsControl
provides item presentation and
data binding support, but does not offer item selection—this lets you
present a list of items without being forced to make them selectable.
Use the Selector
base class if you
require selection.
Chapter 5 describes how to use ItemsControl
and the various list controls
derived from it. Chapter 7 describes how
to use data binding with these controls.
I wanted to highlight some of the similarities and some of the differences of ListBox vs ItemsControl.
Similarites of ItemsControl, ListBox, and ListView
These two controls are similar in a few ways.
- All three are lists
- All three support binding ItemsSource to a list
- All three are ItemsControl objects as ListBox and ListView are descendants
Differences between ItemsControl, ListBox, and ListView
Inheritence
ItemsControl
ItemsControl uses an ItemsPresenter to present its children.
System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.FrameworkElement
System.Windows.Controls.Control
System.Windows.Controls.ItemsControl
ListBox
A ListBox is an ItemsControl but an ItemsControl is not a list box. Notice a list box is a descendant of ItemsControl but has a Selector object, which is abstract, that it specifically derives from. Inheriting from Selector provides ListBox with selection events and selection features that are missing from ItemsControl. ListBox adds a SelectionMode Dependency Property that allows for selection types of Single, Multiple, or Extended, which are defined in a SelectionMode enum. It uses ListBoxItem as its default child.
…
System.Windows.Controls.ItemsControl
System.Windows.Controls.Primitives.Selector
System.Windows.Controls.ListBox
ListView
ListView inherits from ListBox, so it is everything a ListBox is plus it has a View Dependency Property and some functions supporting the View Dependency Property. It uses ListViewItem as its default child.
…
System.Windows.Controls.ItemsControl
System.Windows.Controls.Primitives.Selector
System.Windows.Controls.ListBox
System.Windows.Controls.ListView
Sizing and Scrolling
- ItemsControl takes as much space as it needs for its child elements, which can cause it to be larger than the screen. Because its size is based on its child controls, ItemsControl does not resize when re-sizing the screen.
- ListBox and ListView take up all the space available to them from the parent and no more. Because the size is based on the parent control size, ListBox and ListView resize with the screen.
- ItemsControl does not have a ScrollBar.
- ListBox has both a vertical and horizontal ScrollBar.
Note: I learned that if you want to have an ItemsControl, but you want to have the scrolling. Simply make a copy of the ListBox style and change its TargetType to ItemsControl and use that style.
Styles and Templates
Note: These default styles are obtained using Expresion Blend by right-clicking a Control and choosing Edit Template | Edit a copy.
ItemsControl Default Style
This style is short and simple.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="ItemsControlDefaultStyle" TargetType="{x:Type ItemsControl}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ItemsControl}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Resource dictionary entries should be defined here. --> </ResourceDictionary>
ListBox and ListView Default Style
ListBox and ListView have the same default style, with the only exception being the the TargetType, which is of course ListBox or ListView repectively.
Both have all the elements ItemsControl has, but also there are more Setters as Setters exist for the ScrollViewer and for the Border. ListBox and ListView styles also include a ScrollViewer in the ControlTemplate between the Border and the ItemsPresenter. ListBox and ListView also have a ControlTemplate.Triggers section.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="ListBorder" Color="#828790"/> <Style x:Key="ListBoxDefaultStyle" TargetType="{x:Type ListBox}"> <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/> <Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/> <Setter Property="ScrollViewer.CanContentScroll" Value="true"/> <Setter Property="ScrollViewer.PanningMode" Value="Both"/> <Setter Property="Stylus.IsFlicksEnabled" Value="False"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true"> <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </ScrollViewer> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> </Trigger> <Trigger Property="IsGrouping" Value="true"> <Setter Property="ScrollViewer.CanContentScroll" Value="false"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Resource dictionary entries should be defined here. --> </ResourceDictionary>
Note: If you accidentally put ListBoxItems under ListView, the items are wrapped in a ListViewItem control which has its own margin, which will make the items move 5 pixels further to the right.
Choosing betweeen ItemsControl, ListBox, and ListView
Choosing an ItemsControl
It is pretty easy to choose between ItemsControl and either ListBox or ListView. If you do not want the ability to select a row or switch the View, use ItemsControl. Otherwise, use ListBox or ListView.
Choosing an ListBox
Also, if you need the select feature but you do not need to be able to switch the View, use ListBox.
Choosing an ListView
If you need to be able to switch the View, then choose ListView. It doesn’t matter if you need the ability to select or not.