Search code examples
iosuitableviewmvvmcrossobservablecollectionicommand

MVVMCross iOS how to pass parameter in TableViewCell button


I have a button inside my tableviewcell, and I am trying to pass DataContext as a parameter to a button command inside the tableviewcell. so that a command action can be performed in the view model. Here is my code in the tableviewcell class:

public partial class AssociatedEntCell : MvxTableViewCell
{
    public static readonly NSString Key = new NSString(nameof(AssociatedEntCell));

    private const string BindingText = "AssociatedEnt Username";

    public AssociatedEntCell(IntPtr handle) : base(BindingText, handle)
    {
        InitialiseBindings();
    }

    private void InitialiseBindings()
    {
        this.DelayBind(() =>
        {
            var set = this.CreateBindingSet<AssociatedEntCell, AssociationItemViewModel>();

            set.Bind(btnDeleteAssociation).To(vm => vm.DeleteAssociationCommand).CommandParameter(this.DataContext);
            set.Apply();
        });
    }

    public string AssociatedEnt { get { return lblAssociatedName.Text; } set { lblAssociatedName.Text = value; } }

}

}

It works perfectly the first time; but once I perform clear and add operations on the associated ObservableCollection, the DataContext is not updated, and I get the same old DataContext as before. Below is the ViewModel snippet for the ObservableCollection:

    private MvxObservableCollection<AssociationItemViewModel> associatedEntities;
    public MvxObservableCollection<AssociationItemViewModel> AssociatedEntities
    {
        get { return associatedEntities; }
        set { SetProperty(ref associatedEntities, value); }
    }

    private async Task LoadAssociations()
    {
        Dispatcher.RequestMainThreadAction(() => { 
            AssociatedEntities.Clear();
        });

        //Fetching the list from API
        var res = await businessFacade.GetAssociations(entityID, true);

            if (res == null || !res.Any())
            {
                return;
            }

            foreach (var item in res)
            {
                var associationItem = new AssociationItemViewModel
                {
                    AccountName = item.acname,
                    AccountNum = item.acnum.GetValueOrDefault(),
                    UserID = item.usrid.GetValueOrDefault(),
                    Username = item.usrname,
                    DeleteAssociationCommand = this.DeleteAssociationCommandInit
                };

                Dispatcher.RequestMainThreadAction(() => { 
                AssociatedEntities.Add(associationItem);
                });
            }
        }
    }

Other than the DataContext, The view however, does not lose its binding, and the tableview displays the new updated rows same as in the ObservableCollection.

Is there a way to get the updated DataContext for the command? or any possible method to know the real indexPath even after the changes made to the observablecollection?


Solution

  • I ended up using a separate property for holding the index path instead, like so:

    My TableviewSource:

       protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
        {
            var cell = (AssociatedEntCell)tableView.DequeueReusableCell(AssociatedEntCell.Key);
    
            if (cell != null)
            {
                cell.Index = indexPath.Row;
            }
    
            return cell;
        }
    

    And my Cell:

    public partial class AssociatedEntCell : MvxTableViewCell
    {
        public static readonly NSString Key = new NSString(nameof(AssociatedEntCell));
    
        private const string BindingText = "AssociatedEnt Username; AssociatedUserID UserID";
    
        public AssociatedEntCell(IntPtr handle) : base(BindingText, handle)
        {
            InitialiseBindings();
        }
    
        private void InitialiseBindings()
        {
            this.DelayBind(() =>
            {
                var set = this.CreateBindingSet<AssociatedEntCell, AssociationItemViewModel>();
    
                set.Bind(btnDeleteAssociation).To(vm => vm.DeleteAssociationCommand).CommandParameter(this.Index);
    
                set.Apply();
            });
        }
    
        public string AssociatedEnt { get { return lblAssociatedName.Text; } set { lblAssociatedName.Text = value; } }
    
        public int AssociatedUserID { get; set; }
    
        public int Index { get; set; }
    
    }