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.

Community
  • 1
  • 1
Lynn Crumbling
  • 12,985
  • 8
  • 57
  • 95

1 Answers1

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}}"/>
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • 2
    @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. – BradleyDotNET Jul 16 '15 at 00:14
  • 1
    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? – HaloMediaz Mar 26 '16 at 05:37
  • 1
    @HaloMediaz In Bradley's example, it just has to be an `IEnumerable`, but it really doesn't matter. Your converter handles that. – Lynn Crumbling Jul 12 '16 at 13:47