Getting index of an item in an ObservableCollection inside the item
Asked Answered
H

1

5

I'd like to be able to display an index value from within a DataTemplate, but I don't want the data to be persisted or backed by the model or viewmodel. In other words, if the order of the items in the OC changes, I don't want to have to recalculate the indexes. The value should be intrinsically tied to the underlying index in the OC. It is okay if the index is 0-based (in fact, I'd expect it).

One method that others have used is the AlternationIndex AP, but this has its own pitfalls for certain situations.

One last thought: I can't help but think that a converter is going to be helpful in a final solution.

Hephaestus answered 15/7, 2015 at 17:11 Comment(0)
B
9

I would use a converter to do this.

The trick is giving it the source collection, either on the ConverterParameter or a Dependency Property. At that point, conversion is as simple as using IndexOf.

Here's a sample converter that does this:

public class ItemToIndexConverter : IValueConverter
{
    public object Convert(...)
    {
        CollectionViewSource itemSource = parameter as CollectionViewSource;
        IEnumerable<object> items = itemSource.Source as IEnumerable<object>;

        return items.IndexOf(value as object);
    }

    public object ConvertBack(...)
    {
        return Binding.DoNothing;
    }
}

You can make the implementation strongly typed, return a formatted string as a number, etc. The basic pattern will be as above though.

This implementation uses the parameter approach, as making a DP is more messy in my view. Because you can't bind ConverterParameter, I have it set to a static resource that is bound to the collection:

<CollectionViewSource x:Key="collectionSource" Source="{Binding Path=MyCollection}" />

...

<TextBlock Text="{Binding Converter={StaticResource ResourceKey=ItemToIndexConverter}, 
               ConverterParameter={StaticResource ResourceKey=collectionSource}}"/>
Benadryl answered 15/7, 2015 at 17:12 Comment(3)
@Rachel In reasonable scale I wouldn't think so. Its certainly less efficient than binding against data that is updated once (with one iteration of the collection). So unless your collection is huge and changing frequently, I think this is safe. The real problem is all the extra enumerations (time complexity O(n log n) if I'm not mistaken). Of course, the OP asked for solutions that didn't involve what is necessary for the more efficient approach. Under the given constraints, this is the best I can come up with.Benadryl
I just found this thread via google. This solution seems to work, except that IEnumerable doesn't have an indexof method. The problem is that I cannot cast it to an actual collection, rather than an interface, as I don't know what the collection type is. Does anybody know what the type of CollectionViewSource.source is?Cavity
@Cavity In Bradley's example, it just has to be an IEnumerable<object>, but it really doesn't matter. Your converter handles that.Hephaestus

© 2022 - 2024 — McMap. All rights reserved.