如何使用MvvmCross流畅的API将RecyclerView项目的TextView绑定到Android上ViewModel的属性?

我在我的Xamarin Android项目中使用MvvmCross 。 我有一个MvxActivityMvxRecyclerView ,我已在其布局文件中分配了一个项目模板。

  

ViewModel非常简单,它只包含一个属性,用于保存要在RecyclerView显示的数据:

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

通常,我喜欢尽可能多地使用MvvmCross流畅的API,因为隐式重构支持。 所以在我的活动中,我绑定了MvxRecyclerView的属性,如下所示:

 var recyclerView = View.FindViewById(Resource.Id.my_recycler_view); var set = this.CreateBindingSet(); set.Bind(recyclerView) .For(v => v.ItemsSource) .To(vm => vm.ViewModelItems); set.Apply(); 

到现在为止还挺好。 现在,项目模板的布局文件基本上只包含一个TextView

    

我的ViewModelItem类看起来像这样:

 public class ViewModelItem { public string Title { get; set; } } 

我现在的问题是,如何以及在何处使用流畅的API将TextView.Text属性绑定到ViewModelItem.Title属性?

我知道通过在项目模板布局文件中提供MvxBind属性,没有流畅的API很容易,但我真的更喜欢流畅的API解决方案。

inheritance自MvxRecyclerAdapter并为RecyclerView创建自定义适配器。 覆盖OnCreateViewHolder并返回自定义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); } } 

在此ViewHolder中,您可以使用Fluent API进行绑定。

 public class MyViewHolder : MvxRecyclerViewHolder { private readonly TextView textView; public MyViewHolder(View itemView, IMvxAndroidBindingContext context) : base(itemView, context) { this.textView = itemView.FindViewById(Android.Resource.Id.Text1); this.DelayBind(() => { var set = this.CreateBindingSet(); set.Bind(this.textView).To(x => x.Title); set.Apply(); }); } } 

在您的Activity中创建适配器并将其添加到RecyclerView:

 var adapter = new MyAdapter((IMvxAndroidBindingContext)this.BindingContext); recyclerView.Adapter = adapter; 

并将您的项目绑定到您的适配器的ItemsSource:

 set.Bind(this.adapter).For(x => x.ItemsSource).To(x => x.ViewModelItems); 

根据Ken的回答,我创建了几个支持类和扩展来概括项目的绑定,并将它们与使用示例一起推送到github:

https://github.com/lauxjpn/MvxItemBinder

它允许您编写项目绑定,如下所示:

 var recyclerView = FindViewById(Resource.Id.RecyclerView); var set = this.CreateBindingSet(); set.Bind(recyclerView) .For(v => v.ItemsSource) .To(vm => vm.Items); set.Apply(); recyclerView.BindItems(this, (itemView, itemSet) => itemSet.Bind(itemView.FindViewById(Resource.Id.item_template)) .For(v => v.Text) .To(vm => vm.Title) ); 

甚至更短:

 var recyclerView = FindViewById(Resource.Id.RecyclerView); var set = this.CreateBindingSet(); set.Bind(recyclerView.BindItems(this, (itemView, itemSet) => itemSet.Bind(itemView.FindViewById(Resource.Id.item_template)) .For(v => v.Text) .To(vm => vm.Title))) .For(v => v.ItemsSource) .To(vm => vm.Items); set.Apply();