How Can a Separator Be Added Between Items in an Itemscontrol

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.

(WPF) How can a separator be added between items in an ItemsControl - Bug Fixing

It was not easy,but I realized what shall I do to fix this bug. My idea is to use custom Convertor, but I haven't any clever thoughts How to send ConverterParameter into convertor. But I've found solution.
Here is my convertor:

public class SeparatorConverter : IValueConverter
{
private Visibility _visible;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var element = (TextBlock) value;
element.Loaded += ElementLoaded;
return _visible;
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null; //not needed
}
private static void ElementLoaded(object sender, RoutedEventArgs e)
{
var element = sender as TextBlock;
var parentItemsControl = element.FindParent(x => x is ItemsControl) as ItemsControl;
var parentPanel = element.FindParent(x => x is Panel) as Panel;

if (parentItemsControl == null || element == null || parentPanel== null)
return;

var itemText = parentPanel.FindName("MyTextBlock") as TextBlock;
var collection = parentItemsControl.ItemsSource as IEnumerable<string>;

if (itemText == null || collection == null)
return;

var list = collection.ToList();
if (list.IndexOf(itemText.Text) == list.Count() - 1) // Can be incorrect because we can have two same items
element.Visibility = Visibility.Collapsed;
}
}

Find parent function:

public static DependencyObject FindParent(this DependencyObject element, Func<DependencyObject, bool> filter)
{
DependencyObject parent = VisualTreeHelper.GetParent(element);

if (parent != null)
{
if (filter(parent))
{
return parent;
}

return FindParent(parent, filter);
}

return null;
}

Here is my XAML code:

  <Coverters:SeparatorConverter x:Key="SeparatorVisibilityConverter">
</Coverters:SeparatorConverter>
<ItemsControl Grid.Row="1" ItemsSource="{Binding Value, IsAsync=False}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock x:Name="MyTextBlock" Text="{Binding}" Style="{StaticResource TextBlockInListViewItem}" TextWrapping="WrapWithOverflow"/>
<TextBlock x:Name="commaTextBlock" Style="{StaticResource TextBlockInListViewItem}" Text=", " Visibility="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource SeparatorVisibilityConverter}}"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Ok. Any way, If you have another idea how to fix this bug, you could post your answer here=)

WPF how to put separator below each item in horizontal stackpanel

make the first stackpanel vertical and put the content control and the label inside of a horizontal stackpanel. something like this:

<StackPanel>
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource Appbar_Suitcase}" />
<Label Content="{Binding Name}"/>
</StackPanel>

<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
</StackPanel>

ListView separator between items

You need to use a DataTemplateSelector for this. First you need to create Two DataTemplate's

For example: In a simple ItemsControl which I want to show you a list of String, My Two DataTemplate's would look like below.

<Page.Resources>  
<DataTemplate x:Name="AllItems">
<Border BorderBrush="{StaticResource SystemControlBackgroundBaseLowBrush}" BorderThickness="0,0,0,2">
<TextBlock Text="{Binding ''}" Padding="10" Margin="10,0" />
</Border>
</DataTemplate>
<DataTemplate x:Name="LastItems">
<TextBlock Text="{Binding ''}" Padding="10" Margin="10,0" />
</DataTemplate>
</Page.Resources>

Now I create a DataTemplateSelector and Check if the Item that I need to apply the DataTemplate is Last one or not.

public class ItemsDataTemplateSelector: DataTemplateSelector
{
public DataTemplate AllItems { get; set; }
public DataTemplate LastItems { get; set; }

protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
DataTemplate _returnTemplate = new DataTemplate();
var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
if (itemsControl.IndexFromContainer(container) == (itemsControl.ItemsSource as List<String>).Count-1)
{
_returnTemplate = LastItems;
}
else
{
_returnTemplate = AllItems;
}
return _returnTemplate;
}
}

Now my ItemsControl Implementation would be

<ItemsControl x:Name="listView">  
<ItemsControl.ItemTemplateSelector>
<local:ItemsDataTemplateSelector AllItems="{StaticResource AllItems}" LastItems="{StaticResource LastItems}" />
</ItemsControl.ItemTemplateSelector>
</ItemsControl>

Here is how i set the ItemsSource to ItemsControl

List<String> items = new List<string>();  
for (int i = 1; i <= 5; i++)
{
items.Add("Item " + i.ToString());
}
listView.ItemsSource = items;

Below is your output. You can see Last Item does not have a Border

Sample Image

Separator in ItemsControl renders in different shades for each item

Try SnapsToDevicePixels="True"

<ItemsControl ItemsSource="{Binding Path=Items}" SnapsToDevicePixels="True">

If this doesn't help you can also try with

  • UseLayoutRounding="True" (WPF 4)
  • RenderOptions.EdgeMode="Aliased" (Turn of anti-aliasing)

Text separator between ListView in WPF

Duplicate of How can a separator be added between items in an ItemsControl, try this:

<ItemsControl Name="theListBox">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="seperator" Text=" | "/>
<TextBlock Text="{Binding}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="seperator" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Stretching the items of an ItemsControl

You have two columns in your main (outer) grid, yet you use only the first column.
The second column uses all the remaining space.



Related Topics



Leave a reply



Submit