How to know which item in a ListView is being clicked and then perform an operation on that item?

I have a ViewCell that's bound to a model, which is generated in a ContentPage. In the ContentPage I have something like this:

List<Item> myList = new List<Item>();
ListView myListView = new ListView();

getItems();  // Fills up the list with Items from a database

myListView.HasUnevenRows = true;
myListView.ItemsSource   = myList;
myListView.ItemTemplate  = new DataTemplate(typeof(ItemEntry));  // Is there any way to use a constructor for ItemEntry that has parameters?

eventsListStack.VerticalOptions = LayoutOptions.FillAndExpand;
eventsListStack.Children.Add(myListView);

Content = new StackLayout
{
    Children = 
    {
        eventsListStack,
    }
};

I'd like to setup a clickable event that deletes an Item in the list when the Item (not a button but have the entire Item clickable) is clicked. So I somehow need to have a reference to the specific Item clicked and then remove it from the myList via myList.Remove(Item). I was thinking to have a reference to the ContentPage passed in the constructor of the ItemEntry, and then have this bit of code within ItemEntry:

public ItemEntry(ContentPage ContentPageReference) {  // ViewCell custom constructor
[...]
var itemClick = new TapGestureRecognizer();
itemClick.Tapped += (s, e) => ContentPageReference.OnEventClicked(itemID);
ItemStackLayout.GestureRecognizers.Add(itemClick);
}

So each Item would then send the itemID to the ContentPage's OnEventClicked(string itemID) so that I can delete it there from the list, but unfortunately there doesn't seem to be a way to call the custom constructor with a parameter when binding the DataTemplate. Is there any other way for me to setup a click event and know which Item is being clicked in the list?

Best Answers

  • RaphaelSchindlerRaphaelSchindler ✭✭✭ US ✭✭✭
    Accepted Answer

    Why don't you just use myListView.ItemTapped

  • JoeMankeJoeManke ✭✭✭✭✭ US ✭✭✭✭✭
    Accepted Answer

    ListView.ItemSelected and Binding is the way to go.

    public class MyPage : ContentPage
    {
        // ObservableCollection, so that when the list changes, the UI will update automatically
        private ObservableCollection<Item> _myList;
        public ObservableCollection<Item> MyList
        {
            get
            {
                return _myList;
            }
            private set
            {
                _myList = value;
                OnPropertyChanged();
            }
        }
    
        public MyPage()
        {
            BindingContext = this;
    
            _myList = getItems();  // Fills up the list with Items from a database
    
            ListView myListView = new ListView()
            {
                myListView.HasUnevenRows = true,
                myListView.ItemTemplate  = new DataTemplate(typeof(ItemEntry)),
            };
            myListView.SetBinding(ListView.ItemsSourceProperty, nameof(MyList));
            myListView.ItemSelected += ItemSelected;
    
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.FillAndExpand,
                Children = 
                {
                    eventsListStack,
                }
            };
        }
    
        private void ItemSelected(object sender, ItemTappedEventArgs e)
        {
            Item selected = e.SelectedItem as Item;
    
            MyList.Remove(selected);
        }
    }
    
  • ShantimohanElchuriShantimohanElchuri ✭✭✭✭✭ US ✭✭✭✭✭
    Accepted Answer

    ObservableCollection will respond to the changes to the collection attached to the ItemsSource where as List will be a dumb one and mostly not useful.

Answers

  • RaphaelSchindlerRaphaelSchindler ✭✭✭ USMember ✭✭✭
    Accepted Answer

    Why don't you just use myListView.ItemTapped

  • JoeMankeJoeManke ✭✭✭✭✭ USMember ✭✭✭✭✭
    Accepted Answer

    ListView.ItemSelected and Binding is the way to go.

    public class MyPage : ContentPage
    {
        // ObservableCollection, so that when the list changes, the UI will update automatically
        private ObservableCollection<Item> _myList;
        public ObservableCollection<Item> MyList
        {
            get
            {
                return _myList;
            }
            private set
            {
                _myList = value;
                OnPropertyChanged();
            }
        }
    
        public MyPage()
        {
            BindingContext = this;
    
            _myList = getItems();  // Fills up the list with Items from a database
    
            ListView myListView = new ListView()
            {
                myListView.HasUnevenRows = true,
                myListView.ItemTemplate  = new DataTemplate(typeof(ItemEntry)),
            };
            myListView.SetBinding(ListView.ItemsSourceProperty, nameof(MyList));
            myListView.ItemSelected += ItemSelected;
    
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.FillAndExpand,
                Children = 
                {
                    eventsListStack,
                }
            };
        }
    
        private void ItemSelected(object sender, ItemTappedEventArgs e)
        {
            Item selected = e.SelectedItem as Item;
    
            MyList.Remove(selected);
        }
    }
    
  • FilipTodorovicFilipTodorovic USMember

    @JoeManke Thanks for the reply! I added the code you suggested, but for some reason I get a NullReferrenceException when I add Items to myList. I tried to initialize _myList with new, but it still did the same thing. I also tried to remove MyList and have _myList be public, and while it didn't crash, the list was empty on screen even if I added Items to it. Any suggestions?

  • ShantimohanElchuriShantimohanElchuri ✭✭✭✭✭ USMember ✭✭✭✭✭

    @FilipTodorovic Did you go through the Working with ListViews sample? It shows how to use the ItemSelected / ItemTapped events.

  • FilipTodorovicFilipTodorovic USMember
    edited September 2015

    @JoeManke Also, is there a real difference in using an ObservableCollection<Item> vs a List<Item> in this case?

  • ShantimohanElchuriShantimohanElchuri ✭✭✭✭✭ USMember ✭✭✭✭✭
    Accepted Answer

    ObservableCollection will respond to the changes to the collection attached to the ItemsSource where as List will be a dumb one and mostly not useful.

  • FilipTodorovicFilipTodorovic USMember

    @JoeManke @ShantimohanElchuri Thanks for all the help, I finally got it to work properly and using an ObservableCollection is definitely the way to go, with a List it just overall breaks the UI rendering items unclickable and removing the last item in the list instead of the one clicked. I appreciate it!

Sign In or Register to comment.