【问题标题】:Distinct item template for first and last item in a ListViewListView 中第一个和最后一个项目的不同项目模板
【发布时间】:2011-10-20 19:55:50
【问题描述】:

我需要对列表视图的第一项和最后一项设置不同的样式。为了实现这一点,我开始研究基于该答案的解决方案:Use different template for last item in a WPF itemscontrol

基本上,我有一个自定义 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;
    }
}

【问题讨论】:

    标签: wpf listview datatemplate


    【解决方案1】:

    作为一种替代方法,我建议将ItemsControlAlternationCount 绑定到集合中的项目数(例如Count 属性)。然后,这将为您的 ItemsControl 中的每个容器分配一个唯一的 AlternationIndex (0, 1, 2, ... Count-1)。请参阅此处了解更多信息:

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

    一旦每个容器都有一个唯一的AlternationIndex,您就可以在容器Style 中使用DataTrigger 来根据索引设置ItemTemplate。这可以使用带有转换器的MultiBinding 来完成,如果索引等于计数,则返回True,否则返回False。当然,您也可以围绕这种方法构建一个选择器。除了转换器之外,这种方法都很好,因为它是仅 XAML 的解决方案。

    一个使用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>
    

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

    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
    }
    

    【讨论】:

    • 我想知道您为什么没有比较使用 Datatrigger 的绑定到 ItemsCount 和 Value 到 AlternationCount?是不是因为 ItemCount 不是依赖属性,它会抛出错误?还是有其他原因?因为我看到它是一个布尔值,等于比较,为什么我们需要一个转换器
    • @ramb00 我试了一下,得到:“不能在‘DataTrigger’类型的‘Value’属性上设置‘Binding’”。看来 Value 不是一个dependencyProp。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2013-11-09
    • 1970-01-01
    • 2017-02-17
    相关资源
    最近更新 更多