web-dev-qa-db-ja.com

WPF ItemsControlは、ItemsSourceの現在のListItemインデックスです。

ItemsControlで現在のアイテムのインデックスを知ることは可能ですか?

[〜#〜] edit [〜#〜]これは機能します!

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

次のようになります。

enter image description here

17
Jerry Nixon

少し前に同じことを聞いた ここ

組み込みのIndexプロパティはありませんが、ItemsControlのAlternationCountをアイテム数よりも大きい値に設定し、AlternationIndexにバインドできます。

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

ListBoxが仮想化を ここで指摘されているbradgonesurfing として使用している場合、このソリューションは機能しない可能性があることに注意してください。

23
Rachel

これは完全な答えではなく、提案です。提案されているようにAlternationIndex手法を使用しないでください。最初はうまくいくようですが、奇妙な副作用があります。 AlternationIndexが0から始まることを保証できないようです。

最初のレンダリングで正しく機能します

enter image description here

ただし、グリッドのサイズを変更してから展開すると、インデックスがゼロから始まらなくなります。下の画像で効果を見ることができます

enter image description here

これは、次の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>

私は別の解決策を探しています:(

8
bradgonesurfing

Alternation Countを使用する場合、AlternationCountAlternationCountであるため、DependencyPropertyプロパティをバインドしているコレクションのアイテムの現在の数にバインドすることもできることに注意してください。

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

それが役に立てば幸い。

6
Johannes Wanzek

はい、そうです! ItemsControlItemContainerGenerator プロパティを公開します。 ItemContainerGeneratorには、特定のアイテムのインデックスを見つけるために使用できるIndexFromContainerなどのメソッドがあります。 ItemsControlをオブジェクトのコレクションにバインドすると、コンテナがそれぞれに自動的に生成されることに注意してください。 ContainerFromItemメソッドを使用して、バインドされた各アイテムのコンテナを見つけることができます。

1
ColinE

より信頼性の高い方法は、値コンバーターを使用して、インデックスを持つ新しいコレクションを生成することです。ヘルパーが2人いると、これはかなり苦痛がありません。 ReactiveUI'sIEnumerable<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);
    }
}

とコンバーター

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

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