2010-08-10 8 views

Trả lời

26

Nếu bạn không sử dụng bất kỳ loại phong cách hàng xen kẽ bạn có thể có thể chiếm quyền điều khiển AlternationIndex cho việc này. Đặt AlternationCount trên ItemsControl của bạn để một cái gì đó lớn hơn số lượng tối đa có thể có của các mục của bạn và sau đó sử dụng

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

Edit: Theo bradgonesurfing pointed out in comments, điều này không được khuyến khích nếu bạn đang sử dụng ảo hóa, vì nó sẽ chỉ index các mục được tạo và không phải toàn bộ danh sách.

+0

Cảm ơn bạn, điều đó chỉ hoạt động tốt trong hoàn cảnh của tôi! – Rachel

+4

Đừng làm điều này. Xem http://stackoverflow.com/questions/6511180/wpf-itemscontrol-the-current-listitem-index-in-the-itemssource/17962582#17962582 – bradgonesurfing

+0

Hữu ích, nhưng nó bắt đầu ở mức 0, điều này không hữu ích trừ khi giao diện người dùng được thiết kế cho các lập trình viên. Tôi tưởng tượng hầu hết mọi người muốn điều này muốn nó bắt đầu tại 1. – Chris

1

Để ghi lại, có một cách khác để thực hiện việc này: sử dụng tùy chỉnh Bộ chuyển đổi. Một chút phức tạp hơn, nhưng bạn không phải lo lắng về 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; 
    } 
} 

mẫu sử dụng:

<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

Cảm ơn, tôi sẽ phải cung cấp cho điều này một shot tiếp theo thời gian tôi cần ItemIndex trong một ItemsControl :) Bạn có bất kỳ vấn đề với hiệu suất sử dụng này? – Rachel

+0

Không, nhưng tôi chỉ sử dụng nó với các mảng tương đối nhỏ. –

3

Dưới đây là một phương pháp tôi sử dụng để thêm một chỉ số bindable trên một mục bộ sưu tập. Tôi về cơ bản bọc mục của tôi trong một container có một chỉ mục, và có một ObservableCollection tùy chỉnh chấp nhận trình bao bọc.

Lưu ý rằng MoveItem không bị ghi đè, nhưng phải thực hiện đầy đủ.

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

sau đó tôi mở rộng lớp wrapper của tôi để có được một tài sản bindable mà tôi có thể kiểm soát như thế nào chỉ số được hiển thị:

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

Sample Cách sử dụng

XAML:

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

Mã số:

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

Tất nhiên, mọi ràng buộc với cá thể MyItem thực tế sẽ phải đi qua thuộc tính của mục IndexedItemContainer.

+0

Cảm ơn. Tôi thường không thích kế thừa từ 'ObservableCollection ', tuy nhiên tôi sẽ ghi nhớ điều này nếu tôi cần một cái gì đó như thế này trong tương lai :) – Rachel