2010-08-10 21 views

Respuesta

26

Si usted no está usando cualquier tipo de alternancia de estilos fila que podría ser capaz de secuestrar el AlternationIndex para esto. Establecer AlternationCount en su ItemsControl a algo más grande que la posible recuento máximo de sus artículos y después utilizar

Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(ItemsControl.AlternationIndex)}" 

Edit: Como bradgonesurfing pointed out in comments, esto no es recomendable si usted está utilizando la virtualización, ya que sólo indexará los elementos que se generan y no toda la lista.

+0

¡Gracias, funcionó muy bien en mi situación! – Rachel

+4

No hagas esto. Ver http://stackoverflow.com/questions/6511180/wpf-itemscontrol-the-current-listitem-index-in-the-itemssource/17962582#17962582 – bradgonesurfing

+0

Útil, pero comienza en 0, lo que no es muy útil a menos que la interfaz de usuario está diseñada para programadores. Me imagino que la mayoría de la gente que quiere esto quiere que comience en 1. – Chris

1

Para el registro, hay otra manera de lograr esto: utilizando el convertidor personalizado . Un poco más complicado, pero no tiene que preocuparse por AlternationCount/Index.

public sealed class ArrayWrapperConverter : IValueConverter 
{ 
    private static readonly Type ArrayWrappingHelperType = typeof(ArrayWrappingHelper<>); 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value == null) 
     { 
      return null; 
     } 

     Type valueType = value.GetType(); 
     if (!valueType.IsArray) 
     { 
      return DependencyProperty.UnsetValue; 
     } 

     Type elementType = valueType.GetElementType(); 
     Type specificType = ArrayWrappingHelperType.MakeGenericType(elementType); 

     IEnumerable wrappingHelper = (IEnumerable) Activator.CreateInstance(specificType, value); 
     return wrappingHelper; 
    } 

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

internal class ArrayWrappingHelper<TValue> : IEnumerable 
{ 
    private readonly TValue[] _array; 

    public ArrayWrappingHelper(object array) 
    { 
     _array = (TValue[]) array; 
    } 

    public IEnumerator GetEnumerator() 
    { 
     return _array.Select((item, index) => new ArrayItemWrapper<TValue>(_array, index)).GetEnumerator(); 
    } 
} 

public class ArrayItemWrapper<TValue> 
{ 
    private readonly TValue[] _array; 
    private readonly int _index; 

    public int Index 
    { 
     get { return _index; } 
    } 

    public TValue Value 
    { 
     get { return _array[_index]; } 
     set { _array[_index] = value; } 
    } 

    public ArrayItemWrapper(TValue[] array, int index) 
    { 
     _array = array; 
     _index = index; 
    } 
} 

Ejemplo de uso:

<Window x:Class="WpfArrayBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:WpfArrayBinding.Converters" 
     xmlns:s="clr-namespace:System;assembly=mscorlib" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <ResourceDictionary> 
      <c:ArrayWrapperConverter x:Key="ArrayWrapperConverter" /> 

      <x:Array Type="{x:Type s:String}" x:Key="MyArray"> 
       <s:String>Foo</s:String> 
       <s:String>Bar</s:String> 
       <s:String>Baz</s:String> 
      </x:Array> 
    </ResourceDictionary> 
    </Window.Resources> 

    <ItemsControl ItemsSource="{Binding Source={StaticResource MyArray}, Converter={StaticResource ArrayWrapperConverter}}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate>     
       <StackPanel Orientation="Horizontal"> 
        <Label Content="{Binding Index}" /> 
        <TextBox Text="{Binding Value}" /> 
       </StackPanel> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Window> 
+0

Gracias, tendré que probar esto la próxima vez que necesite el ItemIndex en un ItemsControl :) ¿Ha tenido algún problema con el rendimiento al usar esto? – Rachel

+0

No, pero lo usé solo con arreglos relativamente pequeños. –

3

Aquí es un método que utiliza para añadir un índice que puede unirse en un elemento de la colección. Básicamente envuelvo mi artículo en un contenedor que tiene un índice, y tengo un ObservableCollection personalizado que acepta el envoltorio.

Tenga en cuenta que MoveItem no se reemplaza, pero tendría que ser para una implementación completa.

public class IndexedItemContainerCollection<T> : ObservableCollection<IndexedItemContainer<T>> 
{ 
    public IndexedItemContainerCollection() 
    { 

    } 

    public IndexedItemContainerCollection(IEnumerable<IndexedItemContainer<T>> collection) 
     : base(collection) 
    { 
     var index = 0; 
     foreach (var item in this) 
     { 
      item.Index = index; 
     } 
    } 

    protected override void InsertItem(int index, IndexedItemContainer<T> item) 
    { 
     item.Index = index; 
     base.InsertItem(index, item); 
     foreach (var indexedItem in this.Where(x=>x.Index > index)) 
     { 
      indexedItem.Index++; 
     } 
    } 

    protected override void RemoveItem(int index) 
    { 
     base.RemoveItem(index); 
     foreach (var indexedItem in this.Where(x => x.Index > index)) 
     { 
      indexedItem.Index--; 
     } 
    } 

} 

public class IndexedItemContainer<T> 
{ 
    public int Index { get; set; } 
    public T Item { get; set; } 
} 

luego extiendo mi clase de contenedor para obtener una propiedad enlazable que tengo control sobre cómo se muestra el índice:

public class NamedIndexedItemContainer<T> : IndexedItemContainer<T> 
{ 
    public string Name 
    { 
     get { return string.Format("Item #{0}", Index + 1); } 
    } 
} 

Ejemplo de uso

XAML:

<ComboBox ItemsSource="{Binding ItemList}"> 
     <ComboBox.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Name}" /> 
      </DataTemplate> 
     </ComboBox.ItemTemplate> 
    </ComboBox> 

Código:

private IndexedItemContainerCollection<MyItem> _itemList; 
public IndexedItemContainerCollection<MyItem> ItemList 
{ 
    get { return _itemList; } 
    set { _itemList= value; OnPropertyChanged(); } 
} 


ItemList = new IndexedItemContainerCollection<MyItem>(); 
var newItem = new NamedIndexedItemContainer<MyItem>() { Item = new MyItem() { ... } }; 
ItemList.Add(newItem); 

Por supuesto, cualquier unión con la instancia myItem real tendría que pasar por artículo propiedad del IndexedItemContainer.

+0

Gracias. Por lo general, no me gusta heredar de 'ObservableCollection ', sin embargo, tendré esto en cuenta si necesito algo como esto en el futuro :) – Rachel

Cuestiones relacionadas