WPF ItemsControl the current ListItem Index in the ItemsSource

后端 未结 5 1006
旧时难觅i
旧时难觅i 2020-12-05 11:10

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

EDIT This works!



    

        
相关标签:
5条回答
  • 2020-12-05 11:41

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

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

    Hope it helps.

    0 讨论(0)
  • 2020-12-05 11:41

    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's IEnumerable<T>.CreateDerivedCollection() and a helper class I wrote for other purposes called 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

     <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>
    
    0 讨论(0)
  • 2020-12-05 11:49

    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.

    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.

    <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 :(

    0 讨论(0)
  • 2020-12-05 11:50

    I asked the same thing a while ago here

    There isn't a built in Index property, but you can set the AlternationCount of your ItemsControl to something higher than your item count, and bind to the 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.

    0 讨论(0)
  • 2020-12-05 11:52

    Yes it is! ItemsControl exposes an ItemContainerGenerator property. The ItemContainerGenerator has methods such as IndexFromContainer which can be used to find the index of a given item. Note that if you bind your ItemsControl to a collection of objects, a container is automatically generated for each. You can find the container for each bound item using the ContainerFromItem method.

    0 讨论(0)
提交回复
热议问题