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.