1

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;
        }
    }
}
d4n13l
  • 126
  • 3
  • 10
  • Have you implemented this as suggested by Stuart here: http://stackoverflow.com/questions/16322879/mvvmcross-and-xcode-storyboard? 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 Jun 23 '14 at 11:15
  • @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: http://stackoverflow.com/questions/22126929/mvvmcross-support-for-xamarin-ios-storyboards The technique being used is his second suggestion. – d4n13l Jun 23 '14 at 13:26
  • Your main issue here is probably something XCode related. Is your "myLabelName" exposed properly? Can you post the code for the MyCell class? – PkL728 Jun 23 '14 at 14:11
  • @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 Jun 23 '14 at 14:22
  • 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 Jun 23 '14 at 15:25
  • @PkL728 I've added the designer to the original post now as well. The data is definitely coming into the cell, it's just the binding that is failing. – d4n13l Jun 23 '14 at 15:28
  • The only thing I see that is different in your set up versus mine is that I have a static UINib Nib defined and when I'm using this in MyView I do my own MyViewSource : MvxTableViewSource with the constructor looking like this: public MyViewSource(UITableView tableView) : base(tableView) { tableView.RegisterNibForCellReuse(CheckoutViewCell.Nib, CheckoutViewCell.Key); } – PkL728 Jun 23 '14 at 16:08
  • My UINib looks like this: public static readonly UINib Nib = UINib.FromName (UserInterfaceIdiomIsPhone ? "MyViewCell_iPhone" : "MyViewCell_iPad", NSBundle.MainBundle); – PkL728 Jun 23 '14 at 16:12
  • is there any more trace near to `Failed to create target binding for binding`? If you put a breakpoint on `set.Apply()` are the UILabel references null? (if they are, then that's the problem to try to solve) – Stuart Jun 24 '14 at 03:46
  • @Stuart Yeah, the labels are null. I cannot for the life of me figure out why. The outlets for the labels are set up normally within XCode. – d4n13l Jun 24 '14 at 14:54
  • Perhaps an issue with XCode? You should open up the story board in XCode with the Source Code Editor and verify that your outlets are set up properly. If you don't get any further I would recommend completely delete the connection nodes and then reimplementing them to see if that changes anything. – PkL728 Jun 30 '14 at 18:39

2 Answers2

4

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

Solution here (my question - the edit is important): https://stackoverflow.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

Community
  • 1
  • 1
pazi146
  • 56
  • 3
  • pazi146 - If you could upload it to github, that would be great. I'm having the same issue, and it would be useful to see the complete solution – rideintothesun Feb 02 '15 at 09:17
2

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.

Adrienjj
  • 23
  • 4