Удалить элемент из списка на Tap

Это мой код:

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);
      });
   }
  }
 }
}

Когда вызывается метод removeItem, представление не обновляется, и элемент не будет удален из ListView, возможно, проблема в CollectionChanged, но я не понимаю, как это исправить.

Примечание. Отладка на устройстве Android

1 ответ

Решение

Пара вещей. Обычно System.ComponentModel.INotifyPropertyChanged используется вместо INotifyCollectionChanged, Если вы переключитесь на это и также реализуете более общий шаблон привязки, ваша ViewModel будет выглядеть так:

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));
    }
}

Я бы также предложил переместить OnPropertyChanged метод и PropertyChanged событие в базовую ViewModel, так что все ваши ViewModel могут наследовать от базы, и у вас не будет дублировать этот код везде.

* Редактировать: только что заметил, что у вас есть TapCommand определены в вашем SchItem учебный класс. Там вы обновляете новый MyGSViewModel экземпляр каждый раз, когда эта команда запускается. Так что, если все в вашем MyGSViewModel установлен на статический (что я не рекомендую), это никогда не повлияет на ваш MyGS стр. В дополнение к тому, что я предложил выше, я бы предложил использовать Tapped событие вместо Command так как вам нужно передать несколько параметров в ваш removeItem метод.

Для этого...

В вашем XAML:

<Button Tapped="OnItemTapped"/>

-ИЛИ ЖЕ-

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

В вашем MyGSContentPage:

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);
    }
}