Simple re-usable Swipe To Delete Xamarin.iOS + MvvmCross

I was recently implementing some swipe to delete and edit mode in my Xamarin.iOS/MvvmCross applications. It is very common that you will have a custom TableViewDataSource that will implement and override some methods to handle this for you. It is very well documented on the Xamarin website. However I have always found myself writing the same code over and over again for custom data source. With MvvmCross we should all be about the code re-use. So I broke it down into this:

  1. A simple IRemove.cs interface that has one ICommand to remove an item.
  2. Implement this interface in ANY ViewModel
  3. A custom MvxStandardTableViewSource that will handle the delete overrides and takes an IRemove class.

That is is really!

Here is the interface:

public interface IRemove
{
  ICommand RemoveCommand { get; }
}

The “MvxDeleteStandardTableViewSource” Impelemtnation

public class MvxDeleteStandardTableViewSource : MvxStandardTableViewSource
{

  private IRemove m_ViewModel;


#region Constructors
  public MvxDeleteStandardTableViewSource(IRemove viewModel, UITableView tableView, UITableViewCellStyle style, NSString cellIdentifier, IEnumerable<MvxBindingDescription> descriptions, UITableViewCellAccessory tableViewCellAccessory = 0) 
			: base(tableView, style, cellIdentifier, descriptions, tableViewCellAccessory)
  {
    m_ViewModel = viewModel;
  }


  public MvxDeleteStandardTableViewSource(IRemove viewModel, UITableView tableView, string bindingText) : base(tableView, bindingText)
  {
    m_ViewModel = viewModel;
  }

  public MvxDeleteStandardTableViewSource(IRemove viewModel, UITableView tableView, NSString cellIdentifier) : base(tableView, cellIdentifier)
  {
    m_ViewModel = viewModel;
  }

  public MvxDeleteStandardTableViewSource(IRemove viewModel, UITableView tableView) : base(tableView)
  {
    m_ViewModel = viewModel;
  }


  public MvxDeleteStandardTableViewSource(IRemove viewModel, UITableView tableView, UITableViewCellStyle style, NSString cellId, string binding, UITableViewCellAccessory accessory)
			: base(tableView, style, cellId, binding, accessory)
  {
    m_ViewModel = viewModel;
  }
#endregion

  public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
  {
    return true;
  }


  public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
  {
    switch (editingStyle)
    {
      case UITableViewCellEditingStyle.Delete:				
        m_ViewModel.RemoveCommand.Execute(indexPath.Row);
        break;
      case UITableViewCellEditingStyle.None:
        break;
      }
  }

  public override UITableViewCellEditingStyle EditingStyleForRow(UITableView tableView, NSIndexPath indexPath)
  {
    return UITableViewCellEditingStyle.Delete;
  }

  public override bool CanMoveRow(UITableView tableView, NSIndexPath indexPath)
  {
    return false;
  }
}



Here is my implementation in my view model:

private MvxCommand<int> m_RemoveCommand;
public ICommand RemoveCommand
{
get => m_RemoveCommand ?? (m_RemoveCommand = new MvxCommand<int>(i => this.m_List.RemoveAt(i)));
}

Then in your View you will just need to setup this:

m_TableView = new UITableView();
Add(m_TableView);

var source = new MvxDeleteStandardTableViewSource (ViewModel, m_TableView, UITableViewCellStyle.Subtitle, new NSString("my_id"), "TitleText Title;DetailText Subtitle;ImageUrl Image", UITableViewCellAccessory.None);
m_TableView.Source = source;

Boom now you are getting sweet swipe to delete with ease!

I also have a full Gist on GitHub!

The possibilities are endless here as well. Your IRemove interface could also have something like a string for what to say (instead of delete) or a method that returns it based on the index. You could also apply this for the drag/drop as well, which would be pretty simple.