1

I am displaying a ListView using WinUI3. I am showing an array of structs, but is it possible to display an array index that is not part of the struct in XAML?

<ListView>
  <ListView.ItemTemplate>
    <DataTemplate x:DataType="local:MyData">
      <TextBlock Text="{x:Bind Index}"/>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

I saw that in WPF, you can do it like the following, but it results in an error in WinUI3. Is there no such method in WinUI3?

<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=(ItemsControl.AlternationIndex)}" />

1 Answer 1

2

Since it seems that there is not easy way to do this, you should keep track of the index in the item (MyData) itself. But if you can't do that, you can try what I came up with. It works. Visual Studio will yell at you but it works.

First, you need to install the CommunityToolkit.WinUI.Extensions NuGet package.

Then:

public partial class ListViewItemElementToIndexConverter : IValueConverter
{
    private ListView? OwnerListView { get; set; }

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var frameworkElement = value as FrameworkElement;
        OwnerListView ??= frameworkElement?.FindAscendant<ListView>();
        string index = OwnerListView?.Items.IndexOf(frameworkElement?.DataContext).ToString() ?? "-1";
        return index;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
<Page.Resources>
    <local:ListViewItemElementToIndexConverter x:Key="ListViewItemElementToIndexConverter" />
</Page.Resources>

<ListView ItemsSource="{x:Bind ViewModel.MyDataCollection, Mode=OneWay}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:MyData">
            <ListViewItem>
                <TextBlock
                    x:Name="IndexTextBlock"
                    Text="{x:Bind IndexTextBlock, Mode=OneWay, Converter={StaticResource ListViewItemElementToIndexConverter}}" />
            </ListViewItem>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

UPDATE

You need to wrap the DataTemplate content with a ListViewItem unless the DataContext won't be set.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. I tried it, but the DataContext of frameworkElement?.DataContext ends up being null. Do you know why this might be?
Sorry. I forgot to mention that you need to wrap the DataTemplate content with ListViewItem. I updated my answer.
It went very well! Thank you very much.
items.IndexOf(item) approach is a O(n^2) guaranteed perf in most scenarios (1000 items => 1->500000 approx loop). You might want to use listView.IndexFromContainer(listViewItem) which may be better in general (see discussion here): github.com/microsoft/microsoft-ui-xaml/blob/main/src/dxaml/xcp/… but the best is really to put something in the data object itself (or in attached properties if it could support it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.