How can a separator be added between items in an ItemsControl How can a separator be added between items in an ItemsControl wpf wpf

How can a separator be added between items in an ItemsControl


<ItemsControl ItemsSource="{Binding Numbers}">    <ItemsControl.ItemsPanel>        <ItemsPanelTemplate>            <!-- could use a WrapPanel if more appropriate for your scenario -->            <StackPanel Orientation="Horizontal"/>        </ItemsPanelTemplate>    </ItemsControl.ItemsPanel>    <ItemsControl.ItemTemplate>        <DataTemplate>            <StackPanel Orientation="Horizontal">                <TextBlock x:Name="commaTextBlock" Text=", "/>                <TextBlock Text="{Binding .}"/>            </StackPanel>            <DataTemplate.Triggers>                <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">                    <Setter Property="Visibility" TargetName="commaTextBlock" Value="Collapsed"/>                </DataTrigger>            </DataTemplate.Triggers>        </DataTemplate>    </ItemsControl.ItemTemplate></ItemsControl>

I arrived at your question because I was looking for a solution in Silverlight, which does not have a previous data relative source.


The current accepted answer gave me a xaml binding error for every template, which I was concerned could be affecting performance. Instead, I did the below, using the AlternationIndex to hide the first separator. (Inspired by this answer.)

<ItemsControl ItemsSource="{Binding Numbers}" AlternationCount="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}">    <ItemsControl.ItemsPanel>        <ItemsPanelTemplate>            <StackPanel Orientation="Horizontal"/>        </ItemsPanelTemplate>    </ItemsControl.ItemsPanel>    <ItemsControl.ItemTemplate>        <DataTemplate>            <StackPanel Orientation="Horizontal">                <TextBlock x:Name="SeparatorTextBlock" Text=", "/>                <TextBlock Text="{Binding .}"/>            </StackPanel>        <DataTemplate.Triggers>            <Trigger Property="ItemsControl.AlternationIndex" Value="0">                <Setter Property="Visibility" TargetName="SeparatorTextBlock" Value="Collapsed" />            </Trigger>         </DataTemplate.Triggers>        </DataTemplate>    </ItemsControl.ItemTemplate></ItemsControl>


For a more generalized Silverlight-compatible solution, I derived a control from ItemsControl (SeperatedItemsControl). Each item is wrapped in a SeperatedItemsControlItem, just like ListBox's ListBoxItem. The template for SeperatedItemsControlItem contains a seperator and a ContentPresenter. The seperator for the first element in the collection is hidden. You can easily modify this solution to make a horizontal bar seperator between items, which is what I created it for.

MainWindow.xaml:

<Window x:Class="ItemsControlWithSeperator.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:ItemsControlWithSeperator"mc:Ignorable="d"d:DesignHeight="300" d:DesignWidth="400"><UserControl.Resources>    <local:ViewModel x:Key="vm" /></UserControl.Resources><Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vm}">    <local:SeperatedItemsControl ItemsSource="{Binding Data}">        <local:SeperatedItemsControl.ItemsPanel>            <ItemsPanelTemplate>                <StackPanel Orientation="Horizontal" />            </ItemsPanelTemplate>        </local:SeperatedItemsControl.ItemsPanel>        <local:SeperatedItemsControl.ItemContainerStyle>            <Style TargetType="local:SeperatedItemsControlItem">                <Setter Property="Template">                    <Setter.Value>                        <ControlTemplate TargetType="local:SeperatedItemsControlItem" >                            <StackPanel Orientation="Horizontal">                                <TextBlock x:Name="seperator">,</TextBlock>                                <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>                            </StackPanel>                        </ControlTemplate>                    </Setter.Value>                </Setter>            </Style>        </local:SeperatedItemsControl.ItemContainerStyle>    </local:SeperatedItemsControl></Grid>

C# Code:

using System;using System.Windows;using System.Windows.Controls;namespace ItemsControlWithSeperator{    public class ViewModel    {        public string[] Data { get { return new[] { "Amy", "Bob", "Charlie" }; } }    }    public class SeperatedItemsControl : ItemsControl    {        public Style ItemContainerStyle        {            get { return (Style)base.GetValue(SeperatedItemsControl.ItemContainerStyleProperty); }            set { base.SetValue(SeperatedItemsControl.ItemContainerStyleProperty, value); }        }        public static readonly DependencyProperty ItemContainerStyleProperty =            DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(SeperatedItemsControl), null);        protected override DependencyObject GetContainerForItemOverride()        {            return new SeperatedItemsControlItem();        }        protected override bool IsItemItsOwnContainerOverride(object item)        {            return item is SeperatedItemsControlItem;        }        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)        {            //begin code copied from ListBox class            if (object.ReferenceEquals(element, item))            {                return;            }            ContentPresenter contentPresenter = element as ContentPresenter;            ContentControl contentControl = null;            if (contentPresenter == null)            {                contentControl = (element as ContentControl);                if (contentControl == null)                {                    return;                }            }            DataTemplate contentTemplate = null;            if (this.ItemTemplate != null && this.DisplayMemberPath != null)            {                throw new InvalidOperationException();            }            if (!(item is UIElement))            {                if (this.ItemTemplate != null)                {                    contentTemplate = this.ItemTemplate;                }            }            if (contentPresenter != null)            {                contentPresenter.Content = item;                contentPresenter.ContentTemplate = contentTemplate;            }            else            {                contentControl.Content = item;                contentControl.ContentTemplate = contentTemplate;            }            if (ItemContainerStyle != null && contentControl.Style == null)            {                contentControl.Style = ItemContainerStyle;            }            //end code copied from ListBox class            if (this.Items.Count > 0)            {                if (object.ReferenceEquals(this.Items[0], item))                {                    var container = element as SeperatedItemsControlItem;                    container.IsFirstItem = true;                }            }        }        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)        {            base.OnItemsChanged(e);            if (Items.Count > 1)            {                var container = (ItemContainerGenerator.ContainerFromIndex(1) as SeperatedItemsControlItem);                if (container != null) container.IsFirstItem = false;            }            if (Items.Count > 0)            {               var container = (ItemContainerGenerator.ContainerFromIndex(0) as SeperatedItemsControlItem);               if (container != null) container.IsFirstItem = true;           }       }    }    public class SeperatedItemsControlItem : ContentControl    {        private bool isFirstItem;        public bool IsFirstItem         {            get { return isFirstItem; }            set             {                if (isFirstItem != value)                {                    isFirstItem = value;                    var seperator = this.GetTemplateChild("seperator") as FrameworkElement;                    if (seperator != null)                    {                        seperator.Visibility = isFirstItem ? Visibility.Collapsed : Visibility.Visible;                    }                }            }        }            public override void OnApplyTemplate()        {            base.OnApplyTemplate();            if (IsFirstItem)            {                var seperator = this.GetTemplateChild("seperator") as FrameworkElement;                if (seperator != null)                {                    seperator.Visibility = Visibility.Collapsed;                }            }        }    }}