How to get the index of the current ItemsControl item?

后端 未结 5 867
北荒
北荒 2020-12-16 10:54

Is there any way to get the index of the current ItemsControl item in WPF?

For example, I want to do something like:



        
相关标签:
5条回答
  • 2020-12-16 11:12

    I did it via the converter that calculate the index of added element.

    It works one way only. If you delete items somehow or collection changing you shoud to use thomething else. And you shoud to create separate converter for every collection which elements you need to be indexed.

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

    I use it in xaml this way

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

    This draws for me a lines for every element in collection with BaseValue offset for X coordinate.

    0 讨论(0)
  • 2020-12-16 11:13

    I would suggest looking at:

    WPF ItemsControl the current ListItem Index in the ItemsSource

    It explains how to work around the fact that there isn't a built in Index property on the ItemsControl.

    EDIT:

    I tried the following code:

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

    And get a window with three TextBlocks like:

    [Index is 0]
    [Index is 1]
    [Index is 2]
    
    0 讨论(0)
  • 2020-12-16 11:15

    If your goal is to have a button in the ItemTemplate work properly, I would use the DataContext. You should also be able to find the index from the DataContext and ItemsSource using LINQ.

    If using commands

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

    If using events, use the sender.

    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 讨论(0)
  • 2020-12-16 11:16

    Check this out

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

    Converter looks like this

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

    As a result enter image description here

    0 讨论(0)
  • 2020-12-16 11:21

    Here how I get 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>
    

    And the converter:

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

    By this way you can bind every type of collection to the ItemSource and he will be change to ListCollectionView. So the converter will work for different collection type.

    xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    
    0 讨论(0)
提交回复
热议问题