代码之家  ›  专栏  ›  技术社区  ›  herohuyongtao

如何获取当前ItemsControl项的索引?

  •  28
  • herohuyongtao  · 技术社区  · 10 年前

    有没有办法得到当前的索引 ItemsControl 中的项目 WPF ?

    例如,我想做一些事情,比如:

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

    所以在这之后 TextBox 将显示文本 "0" 第二 "1" 第三 "2" ... .

    6 回复  |  直到 10 年前
        1
  •  39
  •   Community kavare    7 年前

    我建议看看:

    WPF ItemsControl the current ListItem Index in the ItemsSource

    它解释了如何解决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 >
    

    并获得一个包含三个文本块的窗口,如:

    [Index is 0]
    [Index is 1]
    [Index is 2]
    
        2
  •  9
  •   Saykor    9 年前

    这里是我如何获取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"
    
        3
  •  7
  •   Maximus    10 年前

    看看这个

     <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

        4
  •  1
  •   CBFT    4 年前

    如果你的目标是让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 }
       }
    }
    
        5
  •  0
  •   Kamerton    6 年前

    我是通过计算添加元素的索引的转换器完成的。

    它只起一种作用。如果你以某种方式删除了项目或更改了收藏,你应该使用其他方法。 您应该为每个需要索引的元素集合创建单独的转换器。

    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偏移量。

        6
  •  0
  •   Martin Braun    3 年前

    有一种方法可以在不使用转换器的情况下完成此操作,并且可以在集合中包含重复项,但这意味着您必须维护一个组织列表,该列表还可以使用 KeyValuePair<int, T> 作为列表项类型。

    下面是字符串列表的示例实现。它将显示按钮内的文本,并将索引绑定到命令参数上:

    #region Items
    
    public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(ObservableCollection<string>), typeof(CulturePicker),
                    new FrameworkPropertyMetadata(new ObservableCollection<string>(),
                            FrameworkPropertyMetadataOptions.None,
                            new PropertyChangedCallback(OnItemsChanged)));
    
    public ObservableCollection<string> Items
    {
        get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
    }
    
    private static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        CulturePicker _this = (CulturePicker)d;
        ObservableCollection<string> oldItems = (ObservableCollection<string>)e.OldValue;
        ObservableCollection<string> newItems = _this.Items;
        if (oldItems != null)
        {
            oldItems.CollectionChanged -= this.Items_CollectionChanged;
        }
        List<KeyValuePair<int, string>> organizedItems = new List<KeyValuePair<int, string>>();
        for (int i = 0; i < newItems.Count; i++)
        {
            organizedItems.Add(new KeyValuePair<int, string>(i, newItems[i]));
        }
        this.OrganizedItems = organizedItems;
        newItems.CollectionChanged += this.Items_CollectionChanged;
    }
    
    private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        List<KeyValuePair<int, string>> organizedItems = new List<KeyValuePair<int, string>>();
        for (int i = 0; i < e.NewItems.Count; i++)
        {
            organizedItems.Add(new KeyValuePair<int, string>(i, (string)e.NewItems[i]));
        }
        this.OrganizedItems = organizedItems;
    }
    
    #endregion
    
    #region OrganizedItems
    
    /// <summary>
    /// OrganizedItems Dependency Property
    /// </summary>
    private static readonly DependencyProperty OrganizedItemsProperty =
            DependencyProperty.Register("OrganizedItems", typeof(List<KeyValuePair<int, string>>), typeof(CulturePicker),
                    new FrameworkPropertyMetadata((List<KeyValuePair<int, string>>)null,
                            FrameworkPropertyMetadataOptions.None,
                            new PropertyChangedCallback(OnOrganizedItemsChanged)));
    
    /// <summary>
    /// Gets or sets the OrganizedItems property. This dependency property 
    /// indicates an organized dictionary with the index of the Items as key and the region itself as value.
    /// </summary>
    private List<KeyValuePair<int, string>> OrganizedItems
    {
        get { return (List<KeyValuePair<int, string>>)GetValue(OrganizedItemsProperty); }
        set { SetValue(OrganizedItemsProperty, value); }
    }
    
    /// <summary>
    /// Handles changes to the OrganizedItems property.
    /// </summary>
    private static void OnOrganizedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        CulturePicker _this = (CulturePicker)d;
        List<KeyValuePair<int, string>> oldOrganizedItems = (List<KeyValuePair<int, string>>)e.OldValue;
        List<KeyValuePair<int, string>> newOrganizedItems = _this.OrganizedItems;
    }
    
    #endregion
    
    <UserControl ...
                 Name="_">
    ...
    <ItemsControl ItemsSource="{Binding OrganizedItems, ElementName=_}">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <WrapPanel />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Button Command="{Binding Command, ElementName=_}" 
                  CommandParameter="{Binding Key}" 
                  Text="{Binding Value}" />
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
    ...
    

    在XAML中,Key是索引,Value是实际项,在本例中是字符串。这个 Command 属性本身不包含在本示例中。此外,请注意,它将在源列表的任何更改上重新创建有组织的列表,这将触发重新渲染并导致大列表的速度变慢。