ListView中第一个和最后一个项目的不同项目模板

Vin*_*rat 10 wpf listview datatemplate

我需要以不同方式设置列表视图的第一个和最后一个项目的样式.为此,我开始基于该答案开发解决方案:在WPF项目控件中为最后一项使用不同的模板

基本上,我有一个自定义的ItemsTemplateSelector,它根据列表视图项中的项索引决定要应用的模板(下面的代码).

它正常工作,除了当列表更新(添加或删除项目)时,模板不会再次被选中(例如,最初,SingleItemTemplate被选中,因为有一个项目.当我添加一个项目到列表,第一项的模板没有切换到FirstItemTemplate).如何强制所有项目的模板选择?

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

F R*_*ell 16

作为一种替代方法,我建议将AlternationCountItemsControl的数据绑定到集合中的项目数(例如Count属性).然后,这将分配给您ItemsControl的唯一容器AlternationIndex(0,1,2,... Count-1).浏览此处获取更多信息:

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

每个容器具有唯一性后,AlternationIndex您可以DataTrigger在容器中使用a Style 来设置ItemTemplate索引的基础.这可以使用MultiBinding带有转换器的转换器,True如果索引等于计数则返回,False否则.当然,你也可以围绕这种方法构建一个选择器.除转换器外,这种方法很好,因为它只是一个XAML解决方案.

使用a的示例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>
Run Code Online (Sandbox Code Playgroud)

转换器可能看起来像这样:

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
}
Run Code Online (Sandbox Code Playgroud)