Separate item template for the first and last items in a ListView

I need to style the first and last list items in different ways. To do this, I started working on a solution based on this answer: Use a different template for the last element in the WPF control

Basically, I have a custom item, ItemsTemplateSelector, that decides to use a template based on the index of the item in the list view items (code below).

It works correctly, except that when the list is updated (an element is added or deleted), templates are not selected again (for example, SingleItemTemplate is selected first because there is one element. Element in the list, this template of the first element does not switch to FirstItemTemplate). How to force a template for all elements?

public class FirstLastTemplateSelector : DataTemplateSelector { public DataTemplate DefaultTemplate { get; set; } public DataTemplate FirstItemTemplate { get; set; } public DataTemplate LastItemTemplate { get; set; } public DataTemplate SingleItemTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { ListView lv = VisualTreeHelperEx.FindParentOfType<ListView>(container); if (lv != null) { if (lv.Items.Count == 1) { return SingleItemTemplate; } int i = lv.Items.IndexOf(item); if (i == 0) { return FirstItemTemplate; } else if (i == lv.Items.Count - 1) { return LastItemTemplate; } } return DefaultTemplate; } } 
+8
listview wpf datatemplate
Oct 20 2018-11-11T00:
source share
1 answer

As an alternative approach, I would suggest binding the AlternationCount your ItemsControl to the number of items in your collection (for example, to the Count property). Then it assigns a unique AlternationIndex (0, 1, 2, ... Count-1) to each container in the ItemsControl . See here for more information:

http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount.aspx

Once each container has a unique AlternationIndex , you can use the DataTrigger in your Style container to set the ItemTemplate based on the index. This can be done using MultiBinding with a converter that returns True if the index is equal to the score, False otherwise. Of course, you can also create a selector around this approach. With the exception of the converter, this approach is good, as it is a XAML solution.

Example using ListBox :

 <Window x:Class="WpfApplication4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:l="clr-namespace:WpfApplication4" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <Collections:ArrayList x:Key="MyCollection"> <System:String>Item One</System:String> <System:String>Item Two</System:String> <System:String>Item Three</System:String> </Collections:ArrayList> <l:MyAlternationEqualityConverter x:Key="MyAlternationEqualityConverter" /> <Style x:Key="MyListBoxItemStyle" TargetType="{x:Type ListBoxItem}"> <Style.Triggers> <DataTrigger Value="True"> <DataTrigger.Binding> <MultiBinding Converter="{StaticResource MyAlternationEqualityConverter}"> <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListBox}}" Path="Items.Count" /> <Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)" /> </MultiBinding> </DataTrigger.Binding> <!-- Could set the ItemTemplate instead --> <Setter Property="Background" Value="Red"/> </DataTrigger> </Style.Triggers> </Style> </Grid.Resources> <ListBox ItemsSource="{Binding Source={StaticResource MyCollection}}" AlternationCount="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}" ItemContainerStyle="{StaticResource MyListBoxItemStyle}" /> </Grid> 

Where the converter might look something like this:

 class MyAlternationEqualityConverter : IMultiValueConverter { #region Implementation of IMultiValueConverter public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values != null && values.Length == 2 && values[0] is int && values[1] is int) { return Equals((int) values[0], (int) values[1] + 1); } return DependencyProperty.UnsetValue; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } #endregion } 
+14
Oct. 20 '11 at 11:28
source share



All Articles