Anoop Vaidya
Anoop Vaidya

Reputation: 46563

MvvmCross binding with NSTableView

After searching multiple blogs and videos I find that to implement the UITableView one can use MvxTableViewController, but what to use for NSTableView?

I do not find any tutorial, example that covers OSX binding TableView using MvvmCross. Any leads will be appreciated.

Upvotes: 2

Views: 205

Answers (1)

Cheesebaron
Cheesebaron

Reputation: 24470

We don't have MvxTableViewController for macOS.

However, if you abstract from that, binding to a NSTableView is very similar to a UITableView on iOS.

private NSTableView _tableView;

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    _tableView = new NSTableView();

    // add constraints or size otherwise

    var source = new MvxTableViewSource(_tableView);
    _tableView.Source = source;

    var set = this.CreateBindingSet<MyViewController, MyViewModel>();
    set.Bind(source).For(v => v.ItemsSource).To(vm => vm.Items);
    set.Apply();
}

This will bind the ViewModel Items to the ItemsSource. However, you will still need to specify what to bind in the cell. The simplest way to do this is to provide a TableColumn.

var column = new MvxTableColumn();
column.Identifier = "First";
column.BindingText = "Text Name";
column.HeaderCell = new NSCell("Example");
_tableView.AddColumn(column);

This will bind the Text property of the TableColumn to Name in the items provided in Items in the ViewModel.

If you need more than this you will need to subclass MvxTableViewSource and override GetOrCreateViewFor and in there provide your own subclass of MvxTableCellView where you do more. This could look something as follows.

public class MyCustomCell : MvxTableCellView
{
    public MyCustomCell(IntPtr handle) : base(handle)
    {
    }

    public MyCustomCell(string bindingText) : base(bindingText)
    {
        this.Frame = new CGRect(0, 0, 100, 50);
        TextField = new NSTextField(new CGRect(50, 0, 100, 50))
        {
            Editable = false,
            Bordered = false
        };

        ImageView = new NSImageView(new CGRect(0, 0, 50, 50));

        AddSubview(TextField);
        AddSubview(ImageView);
        this.Initialize(bindingText);
    }

    private string _imageUrl;
    public string ImageUrl
    {
        get => _imageUrl;
        set
        {
            _imageUrl = value;
            ImageService.Instance.LoadUrl(_imageUrl).Into(ImageView);
        }
    }
}

And the table source:

public class MyTableSource : MvxTableViewSource
{
    private string _bindingText;

    public MyTableSource(NSTableView tableView, string bindingText) : base(tableView)
    {
        _bindingText = bindingText;
    }

    public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
    {
        if (ItemsSource == null)
            return null;

        var item = ItemsSource.ElementAt((int)row);
        var view = new MyCustomCell(_bindingText);

        if (view is IMvxDataConsumer bindable)
            bindable.DataContext = item;

        return view;
    }
}

Then instead of using MvxTableViewSource in the first example, use your own MyTableSource instead:

var source = new MyTableViewSource(_tableView, "Text Name; ImageUrl Url");
_tableView.Source = source;

Where Name and Url are in the Item in the Items bound to the ItemsSource.

Upvotes: 4

Related Questions