1

This is my code:

public partial class MyGS: ContentPage {
  public MyGS() {
    InitializeComponent();
    BindingContext = new MyGSViewModel();
  }


public class MyGSViewModel: INotifyCollectionChanged {
  public event NotifyCollectionChangedEventHandler CollectionChanged;

  public ObservableCollection < SchItem > Items {get;private set;}

  public MyGSViewModel() {
   Items = new ObservableCollection<SchItem>();
   //Item Population 

  public void removeItem(int rid, int lid) {
     SchItem myItem = Items[lid];
     Items.Remove(myItem);
     CollectionChanged ? .Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, myItem));
  }
}

public class SchItem {
  public int realm_id {get;set;}
  public int list_id {get;set;}

  public ICommand TapCommand {
   get {return new Command(() => {
     Debug.WriteLine("COMMAND: " + list_id);
     MyGSViewModel gsvm = new MyGSViewModel();
     gsvm.removeItem(realm_id, list_id);
      });
   }
  }
 }
}

When removeItem method is called the view doesn't refresh and the item will be no deleted from ListView, maybe the problem is about the CollectionChanged but i don't get how to fix that.

Note: Debugging in Android Device

Segamoto
  • 195
  • 1
  • 12

1 Answers1

1

A couple of things. Usually System.ComponentModel.INotifyPropertyChanged is used instead of INotifyCollectionChanged. If you switch to that and also implement a more common binding pattern, your ViewModel would look like this:

public class MyGSViewModel: INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection < SchItem > Items {
        get { return _items; }
        private set {
            if(_items != value) {
                _items = value;
                OnPropertyChanged(); //Execute the event anytime an object is removed or added
            }
        }
    }

    public MyGSViewModel() {
        Items = new ObservableCollection<SchItem>();
        //Item Population
    }

    public void removeItem(int rid, int lid) {
        SchItem myItem = Items[lid];
        Items.Remove(myItem); //If an object is removed, the OnPropertyChanged() method will be run from 'Items's setter
    }

    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) {
        PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}

I would also suggest moving the OnPropertyChanged method and the PropertyChanged event into a base ViewModel so that all of your ViewModels can inherit from the base and you do not have duplicate that code everywhere.

*Edit: Just noticed that you have your TapCommand defined within your SchItem class. In there you are newing up a new MyGSViewModel instance everytime that command is run. So unless everything in your MyGSViewModel is set to static (which I do not recommend), that is not ever going to effect your MyGS page. In addition to what I suggested above, I would suggest using the Tapped event instead of a Command since you need to pass multiple parameters into your removeItem method.

To do that...

In your XAML:

<Button Tapped="OnItemTapped"/>

-OR-

<Label>
  <Label.GestureRecognizers>
    <TapGestureRecognizer Tapped="OnItemTapped"/>
  </Label.GestureRecognizers>
</Label>

In your MyGS ContentPage:

public partial class MyGS : ContentPage {

    private MyGSViewModel _viewModel;

    public MyGS() {
        InitializeComponent();
        BindingContext = _viewModel = new MyGSViewModel();
    }

    private void OnItemTapped(object sender, EventArgs e) {
        SchItem item = (SchItem)((Image)sender).BindingContext;

        if(item == null) { return; }

        _viewModel.removeItem(item.realm_id, item.list_id);
    }
}
hvaughan3
  • 9,734
  • 5
  • 48
  • 71
  • About the edit, i got `System.InvalidCastException: Specified cast is not valid. ` maybe because i have the tap command in Item definition class ? Edit: I got SchItem back and not MyGSViewModel as CommandParameter – Segamoto Nov 20 '16 at 17:34
  • @Segamoto O right, because the `BindingContext` is the object since it is in a `ListView`... so in that case I would definitely recommend using the `Tapped` event. I will edit my answer. – hvaughan3 Nov 20 '16 at 17:53
  • @Segamoto Check now – hvaughan3 Nov 20 '16 at 17:58
  • I get `System.InvalidCastException: Specified cast is not valid.` in ` SchItem item = (SchItem)sender;` – Segamoto Nov 20 '16 at 18:30
  • @Segamoto Then I will need to see the rest of your XAML. You are using a `ListView` binded to your `Items` collection via `ListView.ItemSource` right? If so, what does your `ItemTemplate` look like? – hvaughan3 Nov 20 '16 at 18:31
  • @Segamoto Damn, sorry about that. Really messing up today! Check out the `OnItemTapped` method now. The `sender` is actually the `Image` that your `TapGestureRecognizer` is attached to, so you need the `Image.BindingContext` – hvaughan3 Nov 20 '16 at 18:36