How to get indexes of Xamarin CollectionView Items?

2.9k Views Asked by At

I have a CollectionView:

<CollectionView Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="1" x:Name="SomeCollection"
        ItemsLayout="VerticalList">
<CollectionView.ItemTemplate>
    <DataTemplate>
        <StackLayout Orientation="Horizontal" Padding="3" Spacing="0">
            <Label WidthRequest="90" HeightRequest="20" Text="{Binding SomeItemText}" BackgroundColor="Black" TextColor="White"
               VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
            <Button WidthRequest="36" HeightRequest="36" CornerRadius="0" ImageSource="plus_thick.xml" BackgroundColor="Green"
                Clicked="Duplicate_Clicked" />
            <Button WidthRequest="36" HeightRequest="36" CornerRadius="0" ImageSource="close_thick.xml" BackgroundColor="Red" 
                Clicked="Remove_Clicked" />
        </StackLayout>
    </DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

Every item in the collection has a duplicate and a remove button. By clicking the button I would like to duplicate/remove the item, but CollectionView doesn't have indexes on items.

Could you help me with a custom renderer or even something shorter and simpler?

2

There are 2 best solutions below

6
Cheesebaron On

Instead of using click events, I would bind the buttons to a Command<T>.

This way in the ViewModel where you have your ItemsSource, you can just check what the index is of the Item ViewModel you are passing into the command as parameter. So in the ViewModel add something like this:

public Command<ItemViewModel> RemoveItemCommand { get; }

ctor() // this is the ViewModel constructor
{
    RemoveItemCommand = new Command<ItemViewModel>(DoRemoveItemCommand);
}

private void DoRemoveItemCommand(ItemViewModel model)
{
    // do stuff to remove
    // probably something like:
    Items.Remove(model);
    // or get the index like:
    var index = Items.IndexOf(model);
}

Then you can bind this command like so:

<Button
    WidthRequest="36"
    HeightRequest="36"
    CornerRadius="0"
    ImageSource="close_thick.xml"
    BackgroundColor="Red"
    Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemViewModel}}, Path=RemoveItemCommand}"
    CommandParameter="{Binding}" />
0
Cherry Bu - MSFT On

About getting current collectionview item index by Button command, I do one sample that you can take a look:

 <StackLayout>
        <CollectionView
            x:Name="SomeCollection"
            ItemsLayout="VerticalList"
            ItemsSource="{Binding items}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout
                        Padding="3"
                        Orientation="Horizontal"
                        Spacing="0">
                        <Label
                            BackgroundColor="Black"
                            HeightRequest="20"
                            HorizontalTextAlignment="Center"
                            Text="{Binding SomeItemText}"
                            TextColor="White"
                            VerticalTextAlignment="Center"
                            WidthRequest="90" />
                        <Button
                            BackgroundColor="Green"
                            Command="{Binding BindingContext.duplicatecommand, Source={x:Reference SomeCollection}}"
                            CommandParameter="{Binding}"
                            CornerRadius="0"
                            HeightRequest="36"
                            Text="duplicate item"
                            WidthRequest="36" />
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>

 public partial class Page13 : ContentPage
{
    public ObservableCollection<someitems> items { get; set; }
    public ICommand duplicatecommand { get; set; }
    public Page13()
    {
        InitializeComponent();
        items = new ObservableCollection<someitems>()
        {
            new someitems(){SomeItemText="test 1"},
            new someitems(){SomeItemText="test 2"},
            new someitems(){SomeItemText="test 3"},
            new someitems(){SomeItemText="test 4"},
            new someitems(){SomeItemText="test 5"},
            new someitems(){SomeItemText="test 6"}
        };

        duplicatecommand = new Command<someitems>(getindexfun);
        this.BindingContext = this;
    }
    private void getindexfun(someitems item)
    {
        int index = items.IndexOf(item);
    }
}

public class someitems
{
    public string SomeItemText { get; set; }
}