Search code examples
iosuitableviewxamarinxamarin.iosmvvmcross

How can I modify an UIButton inside a TableViewCell from a TableSource?


What I need

I have a UITableView, and each of its cells have a CustomCheckBox (which is a UIButton) and a label. I want that, when I click the Row (the RowSelected method), the Selected property of said UIButton changes and therefore changes the Image of the clicked UIButton.

I have a CustomCheckBox.cs

public partial class CustomCheckBox : UIButton
{
    public CustomCheckBox(IntPtr handle) : base(handle)
    {
        this.SetImage(UIImage.FromBundle("ic_check_on"), UIControlState.Selected);
        this.SetImage(UIImage.FromBundle("ic_check_off"), UIControlState.Normal);
        this.TouchUpInside += (s, args) =>
        {
            this.Selected = !this.Selected;
        };
    }
}

An ItemCellView.cs

public partial class ItemCellView : MvxTableViewCell
{
    public static readonly NSString Key = new NSString("ItemCellView");
    public static readonly UINib Nib;

    static ItemCCellView()
    {
        Nib = UINib.FromName("ItemCellView", NSBundle.MainBundle);
    }

    public ItemCCellView(IntPtr handle) : base(handle)
    {
        this.DelayBind(() =>
        {
            var set = this.CreateBindingSet<ItemCellView, ItemViewModel>();
            set.Bind(this.lblDescription).To(p => p.Description);
            set.Apply();
        });
    }
}

And a TableSource.cs

public class CoberturasOpcionalesSource : MvxTableViewSource
{
    private PlanMulticoberturaOpcional SelectedItem;
    readonly CotizarMulticoberturaViewModel ViewModel;

    private UIViewController parentView;

    public CoberturasOpcionalesSource(UITableView tableView, CotizarMulticoberturaViewModel viewModel) : base(tableView)
    {
        this.ViewModel = viewModel;
        this.UseAnimations = true;
        this.AddAnimation = UITableViewRowAnimation.Top;
        this.RemoveAnimation = UITableViewRowAnimation.Middle;
        tableView.EstimatedRowHeight = 30.0f;

        tableView.RegisterNibForCellReuse(UINib.FromName(ItemCellView.Key, NSBundle.MainBundle), ItemCellView.Key);
    }

    public override nint NumberOfSections(UITableView tableView)
    {
        return this.ViewModel.ObsCollection.Count;
    }

    public override nint RowsInSection(UITableView tableview, nint section)
    {
        return 1;
    }

    protected override object GetItemAt(NSIndexPath indexPath)
    {
        return this.ViewModel.ObsCollection[indexPath.Section];
    }

    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        tableView.DeselectRow(indexPath, true);

        var cell = (ItemCellView)tableView.DequeueReusableCell(ItemCellView.Key, indexPath);

        cell.btnCheckBox.SendActionForControlEvents(UIControlEvent.TouchUpInside);

        var item = this.ViewModel.ObsCollection[indexPath.Section];
        if (item != null)
        {
            //
        }
    }

    protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
    {
        var cell = (ItemCellView)tableView.DequeueReusableCell(ItemCellView.Key, indexPath);

        return cell;
    }
}

The problem

I have a breakpoint on the TouchUpInsde in the CustomCheckbox.cs. When I touch the row, it stops on the TouchUpInside but it doesn't do anything

The solution

Thanks to @Garfield81. I was creating a new cell on the RowSelected method. I change it for this:

var cell = (ItemCellView)tableView.CellAt(indexPath);

Solution

  • I think the issue is in the RowSelected method you are using DequeResuableCell to get a new cell instead of trying to get access to the one already displaying.

    Instead you need to the use the cellForRow method (or it's Xamarin equivalent) to get the cell that was selected.