MvxRecyclerView Fluent API binding

2019-03-02 08:19发布

I am unable to bind ItemClick from MvxRecyclerView (or its Adapter) to a command on my ViewModel using Fluent API. It works if I put both ItemsSource and ItemClick in the XML so I am not interested in such solution.

I used this post as an excellent guideline (How to use the MvvmCross fluent API to bind a RecyclerView item's TextView to a property of its ViewModel on Android?) and all of that works except that I am unable to bind ItemClick on MvxRecyclerView (or the adapter) to a MainViewModel's command which will take me to the next fragment (ItemsSource works like a charm but its a property and not a command!).

For the sake of brevity, I will not be copying the code from the original post (How to use the MvvmCross fluent API to bind a RecyclerView item's TextView to a property of its ViewModel on Android?) so assume that the MainViewModel from that post has been enhanced with a command ShowItemCommand as such:

public class MainViewModel : MvxViewModel
{
    private IEnumerable<ViewModelItem> _viewModelItems;
    public IEnumerable<ViewModelItem> ViewModelItems
    {
        get { return _viewModelItems; }
        set { SetProperty(ref _viewModelItems, value); }
    }    

    public MvxCommand<ViewModelItem> ShowItemCommand
    {
        get
        {
            return new MvxCommand<ViewModelItem>(selectedItem =>
            {
                ShowViewModel<ViewModelItem>
                (new { itemId = selectedItem.Id });
            });
        }
    }
}

and everything else has been implemented as per the referenced post.

So now, in addition to ItemsSource, I want to wire up ItemClick on the MvxRecyclerView (or the Adapter) to the command. The reason these are interchangeable is that MvxRecyclerView just relays these commands to the Adapter.

Apparently, this should work...but it does not:

adapter.ItemClick = ViewModel.ShowItemCommand;

This does not work either:

set.Bind(recyclerView).For(v => v.ItemClick).To(vm => vm.ShowItemCommand);

2条回答
Lonely孤独者°
2楼-- · 2019-03-02 08:48

When creating a custom MvxRecyclerViewHolder you need to make sure that you assign the Click command over to the ViewHolder. This is done in the OnCreateViewHolder override of your custom adapter.


Example for custom ViewHolder

public class MyAdapter : MvxRecyclerAdapter
{
    public MyAdapter(IMvxAndroidBindingContext bindingContext)
        : base(bindingContext)
    {
    }

    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        var itemBindingContext = new MvxAndroidBindingContext(parent.Context, this.BindingContext.LayoutInflaterHolder);
        var view = this.InflateViewForHolder(parent, viewType, itemBindingContext);

        return new MyViewHolder(view, itemBindingContext)
        {
            Click = ItemClick,
            LongClick = ItemLongClick
        };
    }
}
查看更多
一夜七次
3楼-- · 2019-03-02 09:04

I can't reproduce your issue. I just created a new project, added a RecyclerView and added the following binding:

var set = this.CreateBindingSet<FirstView, FirstViewModel>();
set.Bind(recyclerView).For(v => v.ItemsSource).To(vm => vm.ViewModelItems);
set.Bind(recyclerView).For(v => v.ItemClick).To(vm => vm.ShowItemCommand);
set.Apply();

This works just as expected, where ItemClick triggers the ShowItemCommand. VM's look as follows:

public class ViewModelItem : MvxViewModel
{
    public void Init(string itemId)
    {
        Mvx.Trace($"Showing {itemId}");
    }

    public string Id { get; set; }
}


public class FirstViewModel
    : MvxViewModel
{
    public FirstViewModel()
    {
        ViewModelItems = new ViewModelItem[] {
            new ViewModelItem { Id = "Hello"},
            new ViewModelItem { Id = "World"},
            new ViewModelItem { Id = "Foo"},
            new ViewModelItem { Id = "Bar"},
            new ViewModelItem { Id = "Baz"}
        };
    }

    private IEnumerable<ViewModelItem> _viewModelItems;
    public IEnumerable<ViewModelItem> ViewModelItems
    {
        get { return _viewModelItems; }
        set { SetProperty(ref _viewModelItems, value); }
    }

    public MvxCommand<ViewModelItem> ShowItemCommand =>
        new MvxCommand<ViewModelItem>(DoShowItem);

    private void DoShowItem(ViewModelItem item)
    {
        ShowViewModel<ViewModelItem>(new { itemId = item.Id });
    }
}
查看更多
登录 后发表回答