将命令绑定到MvvmCross中表格单元格内的按钮的正确方法

时间:2018-05-22 16:46:53

标签: xamarin.ios mvvmcross

我试图设置一个项目表(UITableView),每个单元格中都有一个按钮,导航到其项目的详细配置文件。

但我不确定在MvvmCross中正确处理这个问题的方法是什么。我的一些想法:

  • ItemCellView的按钮插座公开并将其绑定在GetOrCreateCellFor
  • ShowItemDetailsCommand传递到每个ItemCellView并将其绑定到
  • 使用从ItemCellViewItemsView的简单回调,而不是绑定
  • 为每个单元格单独MvxViewModel并从那里调用导航服务
public class Item
{
    public string Name { get; set; }
}
public class ItemsViewModel : MvxViewModel
{
    public List<Item> Items { get; }
    public MvxCommand ShowItemDetailsCommand { get; }

    readonly IMvxNavigationService _navigationService;
    readonly IDatabaseService _databaseService;

    public ItemsViewModel(IMvxNavigationService navigationService, IDatabaseService databaseService)
    {
        ShowItemDetailsCommand = new MvxCommand(ShowItemDetails);

        _navigationService = navigationService;
        _databaseService = databaseService;

        Items = _databaseService.SelectItems();
    }

    void ShowItemDetails()
    {
        // not sure how "item" gets here so far
        _navigationService.Navigate<ItemDetailsViewModel, Item>(item);
    }
}
public partial class ItemsView : MvxTableViewController<ItemsViewModel>
{
    public ItemsView() : base("ItemsView", null) {}

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

        TableView = View as UITableView;

        var source = new TableViewSource(TableView);
        var bindings = this.CreateBindingSet<ItemsView, ItemsViewModel>();
        bindings.Bind(source).To(vm => vm.Items);
        bindings.Apply();

        TableView.Source = source;
        TableView.ReloadData();
    }

    public class TableViewSource : MvxTableViewSource
    {
        public TableViewSource(UITableView tableView) : base(tableView)
        {
            TableView.RegisterNibForCellReuse(UINib.FromName("ItemCellView", NSBundle.MainBundle), ItemCellView.kCellId);
        }

        protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
        {
            return TableView.DequeueReusableCell(ItemCellView.kCellId, indexPath) as ItemCellView;
        }
    }
}
public partial class ItemCellView : MvxTableViewCell
{
    public const string kCellId = "item_cell";
    // also has an [Outlet] UIButton in the .designer.cs part

    public ItemCellView(IntPtr handle) : base(handle)
    {
        this.DelayBind(() =>
        {
            var bindings = this.CreateBindingSet<ItemCellView, Item>();
            bindings.Bind(Name).To(i => i.Name);
            bindings.Apply();
        });
    }
}

1 个答案:

答案 0 :(得分:2)

您应该在单元格的构造方法中绑定ItemCellView的按钮:

// MyBtn is my Cell's button outlet
protected ItemCellView(IntPtr handle) : base(handle)
{
    this.DelayBind(() =>
    {
        var bindings = this.CreateBindingSet<MyTableViewCell, Item>();

        // Use this bind to set your button's title
        bindings.Bind(MyBtn).For("Title").To(item => item.Name);

        // This bind is used for binding a command in the Item model
        // CommandParameter can pass your parameter
        bindings.Bind(MyBtn).To(item => item.ShowItemDetailsCommand).CommandParameter(DataContext);

        bindings.Apply();
    });
}

由于在Cell中DataContext已更改为Item模型,因此应在模型类中配置绑定命令:

public class Item
{
    private readonly Lazy<IMvxNavigationService> _navigationService = new Lazy<IMvxNavigationService>(Mvx.Resolve<IMvxNavigationService>);

    public string Name { set; get; }

    private ICommand showItemDetailsCommand;
    public ICommand ShowItemDetailsCommand
    {
        get
        {
            return showItemDetailsCommand ?? (showItemDetailsCommand = new MvxCommand<Item>(ShowItemDetails));
        }
    }
    async void ShowItemDetails(Item item)
    {
        await _navigationService.Value.Navigate<SecondViewModel, Item>(item);
    }
}

最后,您要推送的SecondViewModel将通过事件Prepare()接收此参数:

public class SecondViewModel : MvxViewModel<Item>
{
    public override void Prepare(Item parameter)
    {

    }
}