1
votes

I'm developing an app with MvvmCross which uses storyboards for the UI. Rather than using XIB files for table cells, I'm trying to create the cells from within the storyboard. The storyboard generates the class for the cell fine then inside that class I bind to my model. The cells are being created but the following error occurs upon binding to each label within the cell, where 'MyStringProperty' is the name of the property I'm trying to bind to (either Name, PhoneNumber or Email):

Failed to create target binding for binding Text MyStringProperty

The table is being created the same way as in Stuart's Kitten Cell tutorial, except instead of a XIB I'm using the following line of code to signify using the generated class for the cell:

tableView.RegisterClassForCellReuse(typeof(MyCell), MyCell.Key);

The binding of the data in the cell is also being done the same way as in Stuart's Kitten Cell tutorial.


Here is the code for MyCell

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

    public MyCell(IntPtr handle) : base(handle)
    {
        this.DelayBind(() =>
        {
            var set = this.CreateBindingSet<MyCell, ContactModel>();
            set.Bind(myLabelOne).To(contact => contact.Name);
            set.Bind(myLabelTwo).To(contact => contact.PhoneNumber);
            set.Bind(myLabelThree).To(contact => contact.Email);
            set.Apply();
        });
    }
}

The designer:

[Register ("MyCell")]
partial class MyCell
{
    [Outlet]
    MonoTouch.UIKit.UILabel myLabelOne{ get; set; }

    [Outlet]
    MonoTouch.UIKit.UILabel myLabelTwo{ get; set; }

    [Outlet]
    MonoTouch.UIKit.UILabel myLabelThree{ get; set; }

    void ReleaseDesignerOutlets ()
    {
        if (myLabelOne!= null) {
            myLabelOne.Dispose ();
            myLabelOne= null;
        }

        if (myLabelTwo!= null) {
            myLabelTwo.Dispose ();
            myLabelTwo= null;
        }

        if (myLabelThree!= null) {
            myLabelThree.Dispose ();
            myLabelThree= null;
        }
    }
}
2
Have you implemented this as suggested by Stuart here: stackoverflow.com/questions/16322879/…? In general story board doesn't nicely fit the Mvvm pattern. I'd stick to individual xib files and let your view models handle all the navigation.PkL728
@PkL728 The view models are handling navigation. The storyboard only contains the UI for the views, there are no segues. Stuart paints storyboards in a more positive light here: stackoverflow.com/questions/22126929/… The technique being used is his second suggestion.d4n13l
Your main issue here is probably something XCode related. Is your "myLabelName" exposed properly? Can you post the code for the MyCell class?PkL728
@PkL728 I've added the code for MyCell. Also, I made a mistake with 'myLabelName' it should have been 'MyStringProperty' which is basically a public string in a class. So 'MyStringProperty' would be any one of Name, PhoneNumber or Email. The error message appears for all of them when binding.d4n13l
Could you post your MyCell.designer.cs as well? I'm thinking perhaps the Outlet maybe isn't set up right? Your setup doesn't look different than one of my projects that was working...PkL728

2 Answers

4
votes

I had pretty much the same problem, but I found a solution:

Solution here (my question - the edit is important): https://stackguides.com/questions/24507192/mvvmcross-ios-storyboard-table-binding-not-working

Apparantly fluent binding and Storyboard TableViewCells don't work together well. The same is true for CollectionViewCells (same solution in the end, but you don't need a custom MvxCollectionViewSource - standard is fine)

@stuart probably knows better, as to why these two approaches produce different results

Change your cell to this:

public partial class MyCell : MvxTableViewCell
{
    public static readonly NSString Key = new NSString("MyCell");
    private const string BindingText = @"
MyLabelOneText Name;
MyLabelTwoText PhoneNumber;
MyLabelThreeText EMail";

    public string MyLabelOneText
    {
        get { return myLabelOne.Text; }
        set { myLabelOne.Text = value; }
    }

    public string MyLabelTwoText
    {
        get { return myLabelTwo.Text; }
        set { myLabelTwo.Text = value; }
    }

    public string MyLabelThreeText
    {
        get { return myLabelThree.Text; }
        set { myLabelThree.Text = value; }
    }

    public MyCell(IntPtr handle) : base(BindingText, handle)
    {
    }
}

You also might want to use a custom TableViewSource (or overwrite the necessary constructors in your cell):

public class MyTableViewSource : MvxTableViewSource
{
    private NSString cellIdentifier = new NSString("MyCell");

    public MyTableViewSource(UITableView tableView)
        : base(tableView)
    {
    }

    protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
    {
        return (MyCell)tableView.DequeueReusableCell(cellIdentifier);
    }
}

Fit everything to your needs, the only important part is the call to the base constructor MvxTableViewCell(bindingText, handle)

I can upload the project to GitHub if it is needed

2
votes

I had this same issue and in my case simply subclassing MvxTableViewSource and leaving out the RegisterClassForCellReuse call did the trick. It appears that calling it breaks prototype cells set up in Storyboards.