WPF ItemsControl ItemsSource 中的当前 ListItem 索引

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6511180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:57:13  来源:igfitidea点击:

WPF ItemsControl the current ListItem Index in the ItemsSource

wpfindexingitemscontrol

提问by Jerry Nixon

Is it possible to know the current item's Index in a ItemsControl?

是否可以知道 ItemsControl 中当前项目的索引?

EDITThis works!

编辑这有效!

<Window.Resources>

    <x:Array?Type="{x:Type?sys:String}"?x:Key="MyArray">
        <sys:String>One</sys:String>
        <sys:String>Two</sys:String>
        <sys:String>Three</sys:String>
    </x:Array>

</Window.Resources>

<ItemsControl?ItemsSource="{StaticResource?MyArray}"?AlternationCount="100">
????<ItemsControl.ItemTemplate>
????????<DataTemplate>
????????????<StackPanel?Margin="10">

               <!-- one -->
???????????????<TextBlock?Text="{Binding?Path=.,?
????????????????????StringFormat={}Value?is?{0}}"?/>

               <!-- two -->
????????????????<TextBlock?Text="{Binding?Path=(ItemsControl.AlternationIndex),?
????????????????????RelativeSource={RelativeSource?TemplatedParent},?
????????????????????FallbackValue=FAIL,?
????????????????????StringFormat={}Index?is?{0}}"?/>

               <!-- three -->
????????????????<TextBlock?Text="{Binding?Path=Items.Count,?
????????????????????RelativeSource={RelativeSource?FindAncestor,?
????????????????????????AncestorType={x:Type?ItemsControl}},?
????????????????????StringFormat={}Total?is?{0}}"?/>

????????????</StackPanel>
????????</DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

It looks like this:

它看起来像这样:

enter image description here

在此处输入图片说明

回答by Rachel

I asked the same thing a while ago here

不久前我在这里问了同样的问题

There isn't a built in Index property, but you can set the AlternationCountof your ItemsControl to something higher than your item count, and bind to the AlternationIndex

没有内置的 Index 属性,但您可以将AlternationCountItemsControl 的设置为高于您的项目计数的值,并绑定到AlternationIndex

<TextBlock Text="{Binding 
    Path=(ItemsControl.AlternationIndex), 
    RelativeSource={RelativeSource Mode=TemplatedParent}, 
    FallbackValue=FAIL, 
    StringFormat={}Index is {0}}" />

It should be noted that this solution may not work if your ListBox uses Virtualization as bradgonesurfing pointed out here.

应该注意的是,如果您的 ListBox 使用虚拟化,则此解决方案可能不起作用,正如bradgonesurfing 在此处指出的那样

回答by bradgonesurfing

This is not quite an answer but a suggestion. Do not use the AlternationIndex technique as suggested. It seems to work first off but there are wierd side effects. It seems that you cannot guarantee that the AlternationIndex starts at 0.

这不完全是一个答案,而是一个建议。不要按照建议使用 AlternationIndex 技术。它似乎首先起作用,但有奇怪的副作用。似乎您无法保证 AlternationIndex 从 0 开始。

On first rendering it works correctly

在第一次渲染时它可以正常工作

enter image description here

在此处输入图片说明

but re-sizing the Grid and then expanding results in the index not starting at zero any more. You can see the effect in the below image

但是重新调整网格大小然后扩展导致索引不再从零开始。您可以在下图中看到效果

enter image description here

在此处输入图片说明

This was generated from the following XAML. There are some custom components in there but you will get the idea.

这是从以下 XAML 生成的。那里有一些自定义组件,但您会明白的。

<DataGrid
    VirtualizingPanel.VirtualizationMode="Recycling"
    ItemsSource="{Binding MoineauPumpFlanks.Stator.Flank.Boundary, Mode=OneWay}"
    AlternationCount="{Binding MoineauPumpFlanks.Stator.Flank.Boundary.Count, Mode=OneWay}"
    AutoGenerateColumns="False"
    HorizontalScrollBarVisibility="Hidden" 
    >
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Id">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock 
                            Margin="0,0,5,0"
                            TextAlignment="Right"
                            Text="{Binding RelativeSource={ RelativeSource 
                                                            Mode=FindAncestor, 
                                                            AncestorType=DataGridRow}, 
                                           Path=AlternationIndex}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
         <DataGridTemplateColumn  >
            <DataGridTemplateColumn.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Point ["/>
                    <Controls:DisplayUnits DisplayUnitsAsAbbreviation="True" DisplayUnitsMode="Length"/>
                    <TextBlock Text="]"/>
                </StackPanel>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Controls:LabelForPoint ShowUnits="False" Point="{Binding}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

I am searching for an alternate solution :(

我正在寻找替代解决方案:(

回答by Johannes Wanzek

When you use Alternation Count remember that you can also Bind the AlternationCountproperty to the current count of Items of the collection you are binding to since AlternationCountis a DependencyProperty.

当您使用 Alternation Count 时,请记住,您还可以将AlternationCount属性绑定到您要绑定的集合的当前项目计数,因为它AlternationCount是 a DependencyProperty

AlternationCount="{Binding Path=OpeningTimes.Count,FallbackValue='100'}"

Hope it helps.

希望能帮助到你。

回答by ColinE

Yes it is! ItemsControlexposes an ItemContainerGeneratorproperty. The ItemContainerGeneratorhas methods such as IndexFromContainerwhich can be used to find the index of a given item. Note that if you bind your ItemsControlto a collection of objects, a container is automatically generated for each. You can find the container for each bound item using the ContainerFromItemmethod.

是的!ItemsControl公开ItemContainerGenerator属性。的ItemContainerGenerator具有方法如IndexFromContainer可用于查找给定项的索引。请注意,如果您将您ItemsControl的对象绑定到一组对象,则会为每个对象自动生成一个容器。您可以使用该ContainerFromItem方法找到每个绑定项目的容器。

回答by bradgonesurfing

A more reliable way is to use a value converter to generate a new collection with an index. With a couple of helpers this is pretty painless. I use ReactiveUI'sIEnumerable<T>.CreateDerivedCollection()and a helper class I wrote for other purposes called Indexed.

更可靠的方法是使用值转换器生成带有索引的新集合。有几个帮手,这是非常轻松的。我使用ReactiveUIIEnumerable<T>.CreateDerivedCollection()和我为其他目的编写的辅助类,称为 Indexed。

public struct Indexed<T>
{
    public int Index { get; private set; }
    public T Value { get; private set; }
    public Indexed(int index, T value) : this()
    {
        Index = index;
        Value = value;
    }

    public override string ToString()
    {
        return "(Indexed: " + Index + ", " + Value.ToString () + " )";
    }
}

public class Indexed
{
    public static Indexed<T> Create<T>(int indexed, T value)
    {
        return new Indexed<T>(indexed, value);
    }
}

and the converter

和转换器

public class IndexedConverter : IValueConverter
{
    public object Convert
        ( object value
        , Type targetType
        , object parameter
        , CultureInfo culture
        )
    {
        IEnumerable t = value as IEnumerable;
        if ( t == null )
        {
            return null;
        }

        IEnumerable<object> e = t.Cast<object>();

        int i = 0;
        return e.CreateDerivedCollection<object, Indexed<object>>
           (o => Indexed.Create(i++, o));

    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        return null;
    }
}

and in the XAML I can do

在 XAML 我可以做

 <DataGrid
     VirtualizingPanel.VirtualizationMode="Recycling"
     ItemsSource="{Binding 
         MoineauPumpFlanks.Stator.Flank.Boundary, 
         Mode=OneWay, 
         Converter={StaticResource indexedConverter}}"
     AutoGenerateColumns="False"
     HorizontalScrollBarVisibility="Hidden" 
     >
     <DataGrid.Columns>

         <DataGridTemplateColumn Header="Id">

             <DataGridTemplateColumn.CellTemplate>
                 <DataTemplate>
                     <!-- Get the index of Indexed<T> -->
                     <TextBlock 
                             Margin="0,0,5,0"
                             TextAlignment="Right"
                             Text="{Binding Path=Index}"/>
                 </DataTemplate>
             </DataGridTemplateColumn.CellTemplate>
         </DataGridTemplateColumn>

          <DataGridTemplateColumn Header="Point" >
             <DataGridTemplateColumn.CellTemplate>
                 <DataTemplate>
                     <!-- Get the value of Indexed<T> -->
                     <TextBlock Content="{Binding Value}" />
                 </DataTemplate>
             </DataGridTemplateColumn.CellTemplate>
         </DataGridTemplateColumn>
     </DataGrid.Columns>
 </DataGrid>