0
votes

I am relatively new to Mvvm and MvvmCross. I've encountered a problem in iOS;

This is my delayed binding for my MvxTableViewCell-subclass, which I've put in AwakeFromNib:

this.DelayBind(() =>
{
    var bindingSet = this.CreateBindingSet<MyTableViewCell, MyViewModel>();
    bindingSet.Bind(myLabel).To(vm => vm.Name).WithConversion(debugvalueconverter, base.DataContext);
});

My debugvalueconverter looks like this:

public class DebugValueConverter : IMvxValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                System.Diagnostics.Debug.WriteLine("Converting debug: " + value);
                if (parameter != null)
                {
                    var vm = (MyViewModel)parameter;
                    System.Diagnostics.Debug.WriteLine("Converting debug - name from vm: " + vm.Name);
                }
                return value;
            }

            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return new NotImplementedException();
            }
        }

This generates some odd outputs when I'm starting to recycle cells when dragging in the tableview:

Converting debug: [Name from the cell that's appearing]  
Converting debug - name from vm: [Name from an old cell which got recycled]

I.e. the DataContext doesn't seem to be set correctly in this case, BUT the name-property is set correctly. Why is this happening?

My problem is that I want to use a converter that will do some "advanced" calculations according to what's in a few properties of my ViewModel (I.e. my base.DataContext).

Is this a bug in MvvmCross or am I missing something? Why is not the DataContext set correctly here?

Thanks!

1

1 Answers

1
votes

I don't think you can send in the view model that way to the cell. You need to do the binding in your view and bind your cell to the collection of objects in your view model from the view. Typically I do something like this:

public partial class MainView : MvxViewController
{

    /// <summary>
    /// Views the did load.
    /// </summary>
    /// <summary>
    /// Called when the View is first loaded
    /// </summary>
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        var source = new MvxSimpleTableViewSource(MainTableView, MainInspectionCell.Key, MainInspectionCell.Key);
        MainTableView.Source = source;

        var set = this.CreateBindingSet<MainView, MainViewModel>();

        set.Bind(source).To(vm => vm.Inspections);
        set.Bind(source).For(s => s.SelectionChangedCommand).To(vm => vm.ItemSelectedCommand);

        set.Apply();

        MainTableView.ReloadData();
}

And then for the cell I typically do the binding in the constructor of the cell like so:

public partial class MainInspectionCell : MvxTableViewCell
{
    public static readonly UINib Nib = UINib.FromName("MainInspectionCell", NSBundle.MainBundle);
    public static readonly NSString Key = new NSString("MainInspectionCell");

    public MainInspectionCell(IntPtr handle) : base (handle)
    {
        this.DelayBind(() =>
        {
            var set = this.CreateBindingSet<MainInspectionCell, Inspection>();
            set.Bind(InspectionCell).For(v => v.BackgroundColor).To(vm => vm.StatusColor).WithConversion("NativeColor");
            set.Apply();
        });
    }

    public static MainInspectionCell Create()
    {
        return (MainInspectionCell)Nib.Instantiate(null, null)[0];
    }
}

}

Hope this helps! I think the main issue is that you are trying to send the view model directly into the cell which is not there. If that is something you are needing to accomplish you will need to create some kind of wrapper around your collection object which sends in the view model you need to access.