18 Stimmen

WPF ItemsControl den aktuellen ListItem Index in der ItemsSource

Ist es möglich, den Index des aktuellen Elements in einem ItemsControl zu kennen?

EDIT Das funktioniert!

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

Das sieht folgendermaßen aus:

enter image description here

25voto

Rachel Punkte 126340

Ich habe vor einiger Zeit die gleiche Frage gestellt aquí

Es gibt keine eingebaute Eigenschaft Index, aber Sie können die Eigenschaft AlternationCount des ItemsControls auf einen Wert, der höher ist als die Anzahl der Artikel, und binden Sie an das AlternationIndex

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

Es ist zu beachten, dass diese Lösung möglicherweise nicht funktioniert, wenn Ihre ListBox die Virtualisierung als bradgonesurfing wies hier darauf hin .

11voto

bradgonesurfing Punkte 29536

Dies ist keine richtige Antwort, sondern ein Vorschlag. Verwenden Sie nicht die AlternationIndex Technik wie vorgeschlagen. Es scheint auf den ersten Blick zu funktionieren, aber es gibt merkwürdige Nebenwirkungen. Es scheint, dass Sie nicht garantieren können, dass der AlternationIndex bei 0 beginnt.

Beim ersten Rendering funktioniert es korrekt

enter image description here

aber wenn man die Größe des Gitters ändert und es dann erweitert, wird der Index nicht mehr bei Null beginnt. Sie können den Effekt im folgenden Bild sehen Bild

enter image description here

Diese wurde aus der folgenden XAML generiert. Es gibt einige benutzerdefinierte Komponenten darin, aber Sie werden die Idee bekommen.

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

Ich bin auf der Suche nach einer alternativen Lösung :(

6voto

Johannes Wanzek Punkte 2777

Wenn Sie Alternation Count verwenden, denken Sie daran, dass Sie auch die AlternationCount Eigenschaft auf die aktuelle Anzahl der Elemente der Sammlung, an die Sie gebunden sind, da AlternationCount ist eine DependencyProperty .

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

Ich hoffe, es hilft.

1voto

ColinE Punkte 66577

Ja, das ist es! ItemsControl stellt eine ItemContainerGenerator Eigentum. Die ItemContainerGenerator hat Methoden wie IndexFromContainer die verwendet werden kann, um den Index eines bestimmten Elements zu finden. Beachten Sie, dass wenn Sie Ihre ItemsControl zu einer Sammlung von Objekten, wird für jedes automatisch ein Container erzeugt. Sie können den Container für jedes gebundene Objekt finden, indem Sie die ContainerFromItem Methode.

0voto

bradgonesurfing Punkte 29536

Eine zuverlässigere Methode ist die Verwendung eines Wertkonverters, um eine neue Sammlung mit einem Index zu erstellen. Mit ein paar Hilfsmitteln ist dies ziemlich schmerzlos. Ich verwende ReactiveUI's IEnumerable<T>.CreateDerivedCollection() und eine Hilfsklasse namens Indexed, die ich für andere Zwecke geschrieben habe.

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);
    }
}

und der Konverter

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;
    }
}

und in der XAML kann ich Folgendes tun

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X