web-dev-qa-db-ja.com

現在のItemsControlアイテムのインデックスを取得するにはどうすればよいですか?

ItemsControlの現在のWPFアイテムのインデックスを取得する方法はありますか?

たとえば、私は次のようなことをしたいです:

<ItemsControl>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding current_index}">
            </TextBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

この後、最初のTextBoxにはテキスト"0"、2番目の"1"、3番目の"2" ...が表示されます。

21
herohuyongtao

私は見てみることをお勧めします:

WPF ItemsControl ItemsSourceの現在のListItemインデックス

ItemsControlに組み込みのIndexプロパティがないという事実を回避する方法を説明します。

編集:

私は次のコードを試しました:

<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>
            <TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), 
                RelativeSource={RelativeSource TemplatedParent}, 
                StringFormat={}Index is {0}}">
            </TextBlock>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl >

そして、次のような3つのTextBlockを持つウィンドウを取得します。

[Index is 0]
[Index is 1]
[Index is 2]
31
FishySwede

これをチェック

 <ItemsControl ItemsSource="{Binding Items}" Name="lista">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Vertical">
                    <TextBlock>
                        <TextBlock.Text>
                            <MultiBinding Converter="{StaticResource converter}">
                                <Binding Path="."/>
                                <Binding ElementName="lista" Path="ItemsSource"/>
                            </MultiBinding>
                        </TextBlock.Text>
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

コンバーターはこんな感じ

 public class conv : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<string> lista = (ObservableCollection<string>)values[1];
        return String.Concat(lista.IndexOf(values[0].ToString()), " ", values[0].ToString());
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

結果として enter image description here

7
Maximus

ここで私はItemIndexを取得する方法

<ItemsControl>
        <ItemsControl.Resources>
            <CollectionViewSource x:Key="ProductItems" Source="{Binding SelectedScanViewModel.Products}">
                <CollectionViewSource.SortDescriptions>
                    <componentModel:SortDescription PropertyName="ProductName" Direction="Ascending"/>
                </CollectionViewSource.SortDescriptions>
            </CollectionViewSource>
        </ItemsControl.Resources>
        <ItemsControl.ItemsSource>
            <Binding Source="{StaticResource ProductItems}"/>
        </ItemsControl.ItemsSource>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel HorizontalAlignment="Center">
                    <TextBlock Text="{Binding ProductName}" HorizontalAlignment="Center" />
                    <TextBox Name="txtFocus" Text="{Binding Qty}" MinWidth="80" HorizontalAlignment="Center"
                                     behaviors:SelectTextOnFocus.Active="True">
                        <TextBox.TabIndex>
                            <MultiBinding Converter="{StaticResource GetIndexMultiConverter}" ConverterParameter="0">
                                <Binding Path="."/>
                                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}" Path="ItemsSource"/>
                            </MultiBinding>
                        </TextBox.TabIndex>
                    </TextBox>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="{Binding SelectedScanViewModel.Products.Count}"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

そしてコンバータ:

public class GetIndexMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var collection = (ListCollectionView)values[1];
        var itemIndex = collection.IndexOf(values[0]);

        return itemIndex;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException("GetIndexMultiConverter_ConvertBack");
    }
}

このようにして、すべてのタイプのコレクションをItemSourceにバインドでき、彼はListCollectionViewに変更されます。したがって、コンバーターはさまざまなコレクションタイプで機能します。

xmlns:componentModel="clr-namespace:System.ComponentModel;Assembly=WindowsBase"
4
Saykor

あなたの目標がItemTemplateのボタンを適切に機能させることである場合、私はDataContextを使用します。 LINQを使用して、DataContextおよびItemsSourceからインデックスを見つけることもできるはずです。

コマンドを使用する場合

Command="{Binding DataContext.TestCmd, ElementName=Parent_UC}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Mode=Self}}"

イベントを使用する場合は、送信者を使用します。

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
   if(sender is Button b)
   {
      if(b.DataContext is ClassType t)
      { enter code here }
   }
}
0
CBFT

追加した要素のインデックスを計算するコンバーターを介してそれを行いました。

これは一方向にのみ機能します。何らかの方法でアイテムを削除したり、コレクションを変更したりする場合は、他のものを使用する必要があります。そして、インデックスを付ける必要のある要素ごとに、コレクションごとに個別のコンバーターを作成する必要があります。

public class LineMultiplierConverter : IValueConverter
{
    private int m_lineIndex = 0;
    Line m_curentLine = null;

    /// <summary>
    /// Base value that will be multiplied
    /// </summary>
    public double BaseValue { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var line = value as Line;

        if (line == null)
            return BaseValue;

        bool newLine = line != m_curentLine; //check the reference because this method will called twice on one element by my binding

        if (newLine)
        {
            m_lineIndex++;
            m_curentLine = line; 
        }

        return BaseValue * m_lineIndex;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

このようにxamlで使用します

<UserControl.Resources>
    <sys:Double x:Key="BusinessRowHeight">22</sys:Double>
    <local:LineMultiplierConverter x:Key="LineXConverter" BaseValue="{StaticResource BusinessRowHeight}" />
</UserControl.Resources>
<ItemsControl Grid.Row="1" ItemsSource="{Binding CarBusiness}" Margin="0 5 0 0">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Line StrokeThickness="1" Stroke="LightGray"  
                    X1="0" 
                    Y1="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineXConverter}}" 
                    X2="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl, Mode=FindAncestor}, Path=ActualWidth}" 
                    Y2="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource LineXConverter}}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

これにより、X座標のBaseValueオフセットでコレクション内のすべての要素の線が描画されます。

0
Kamerton