2010-08-10 17 views
23

ItemIndex öğesine ItemsControl öğesinin ItemTemplate içinden bağlanmanın bir yolu var mı? ÖrneğinWPF - Öğeye bağlama Öğe içinden öğe içinden ItemControl?

:

<ItemsControl ItemsSource="{Binding Path=ItemList}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Path=ThisItemsIndex}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

cevap

26

Eğer bunun için AlternationIndex kaçırmak mümkün olabilir alternatif satır stilleri her türlü kullanmıyorsanız. Öğelerinizden maksimum olası sayısı daha fazla olacak şekilde ItemsControl üzerinde AlternationCount getirin ve ardından

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

Edit kullanın: Eğer sanallaştırma kullanıyorsanız bradgonesurfing pointed out in comments gibi bu, tavsiye edilmez istendiğinde sadece indeks öğeleri olarak bu tüm liste oluşturulur ve oluşturulmaz.

+0

Teşekkürler, bu benim durumumda gayet iyi çalıştı! – Rachel

+4

Bunu yapma. Bkz. Http://stackoverflow.com/questions/6511180/wpf-itemscontrol-the-current-listitem-index-in-the-itemssource/17962582#17962582 – bradgonesurfing

+0

Yardımsever, ancak 0'da başlıyor, bu çok yararlı değil. UI programcılar için tasarlanmıştır. Ben bunu istemek çoğu insan 1. 1'de başlamak istiyorum istiyorum. – Chris

1

Kayıt için, bunu başarmanın başka bir yolu vardır: özel Dönüştürücüyü kullanma. Biraz daha karmaşık, ancak AlternationCount/Index hakkında endişelenmenize gerek yok.

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

Örnek kullanım: Burada

<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

Teşekkürler, ben bir ItemsControl içinde ItemIndex bir dahaki sefere bir dahaki sefere vermek zorundayım :) Bunu kullanarak performans ile ilgili herhangi bir sorun yaşadınız mı? – Rachel

+0

Hayır, ancak bunu yalnızca nispeten küçük dizilerle kullandım. –

3

Ben bir koleksiyon öğe üzerinde bir bağlanabilir indeksi eklemek için kullanılan bir yöntemdir. Öğemi temel olarak bir dizini olan bir kapsayıcıya sardım ve sarıcıyı kabul eden özel bir GözlemlenebilirKoleksiyon var.

MoveItem'un geçersiz kılındığını, ancak tam bir uygulama için olması gerektiğini unutmayın.

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

Sonra ben endeksi nasıl görüntüleneceğini üzerinde kontrole sahip bir bağlanabilir özelliği alma benim sarıcı sınıfını genişletmek:

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

Örnek Kullanım

XAML:

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

Kod:

Tabii
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); 

, fiili MyItem örneği ile bağlayıcı herhangi IndexedItemContainer en Ürün mülkiyet geçmesi gerekecekti.

+0

Teşekkürler. Genellikle 'ObservableCollection 'den miras almayı sevmiyorum, ancak gelecekte böyle bir şeye ihtiyacım varsa bunu aklımda tutacağım :) – Rachel