ItemsControl
の現在のWPF
アイテムのインデックスを取得する方法はありますか?
たとえば、私は次のようなことをしたいです:
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding current_index}">
</TextBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
この後、最初のTextBox
にはテキスト"0"
、2番目の"1"
、3番目の"2" ...
が表示されます。
私は見てみることをお勧めします:
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]
これをチェック
<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();
}
}
結果として
ここで私は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"
あなたの目標が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 }
}
}
追加した要素のインデックスを計算するコンバーターを介してそれを行いました。
これは一方向にのみ機能します。何らかの方法でアイテムを削除したり、コレクションを変更したりする場合は、他のものを使用する必要があります。そして、インデックスを付ける必要のある要素ごとに、コレクションごとに個別のコンバーターを作成する必要があります。
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オフセットでコレクション内のすべての要素の線が描画されます。