1

I've been searching for a solution to display the indexes of items from a ListView for a few hours. I can't add a new property to the data source, as an index property to bind to the value.

I've been trying to Bind to a Converter:

    <DataTemplate x:Key="TubeTemplate" x:DataType="data:Tube">
        <local:TubeTemplate HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                            FavoritesNumber="{Binding Converter={StaticResource IndexConverter}}"
                            Closed="TubeTemplate_Closed"></local:TubeTemplate>
    </DataTemplate>

This is the Converter:

public sealed class IndexConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var item = (ListViewItem)value;
        var listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
        int index = listView.IndexFromContainer(item) + 1;
        return index.ToString();
    }

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

The issue is that my code breaks at: var item = (ListViewItem)value;

The value I'm getting is the DataType binded to each item, instead of the ListViewItem.

What Am I doing wrong?

Macaret
  • 797
  • 9
  • 33
  • First: Why can you not add an index property to the model? Second: You're missing the `ConverterParameter` property of the Binding which is what `value` relies on. – Shawn Kendrot Mar 26 '20 at 17:32
  • If only the `Binding` keyword is used, the data model that created this `DataTemplate` will be bound, that is, an instance of the `Tube` class. If you want to get the index, it is recommended to write the index into the `Tube` class and bind the property instead of querying the parent element upwards through the template element – Richard Zhang Mar 27 '20 at 02:13

2 Answers2

4

Use {RelativeSource Mode=TemplatedParent} in the Binding. Then, you can get the ItemContainer with the help of VisualTreeHelper as follows.

<local:TubeTemplate ...
    FavoritesNumber="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource IndexConverter}}"
.../>

and

public object Convert(object value, Type targetType, object parameter, string language)
{
    var presenter = value as ListViewItemPresenter;
    var item = VisualTreeHelper.GetParent(presenter) as ListViewItem;

    var listView = ItemsControl.ItemsControlFromItemContainer(item);
    int index = listView.IndexFromContainer(item) + 1;
    return index.ToString();
}

However, index displayed in this way won't be automatically updated on collection changes. So, if you'll remove some items afterwards, you'd have to implement another function to request each item to reload its index.

ardget
  • 2,561
  • 1
  • 5
  • 4
  • Thank you!. And you are right update having to manually update the index once an item is removed. – Macaret Mar 27 '20 at 07:35
1

Try using AlternationIndex. Also according to this answer, you should use ListViewItem as RelativeSource

In your case, it would look something like

    <DataTemplate>
        <TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), 
            RelativeSource={RelativeSource AncestorType=ListViewItem},
            StringFormat={}Index is {0}}">
        </TextBlock>
    </DataTemplate>
Yura
  • 75
  • 1
  • 8
  • "The member AncestorType is not recognized or is not accessible." and "The property AncestorType was not fount in RelativeSource." – Macaret Mar 26 '20 at 12:42
  • 2
    Sorry, silly mistake FindAncestor doesn't exist in UWP. I'll check is there a way to fix that. – Yura Mar 26 '20 at 13:45