5

我正在使用MvvmCross在我的Xamarin Android項目。我有一個MvxActivityMvxRecyclerView,我已經在其佈局文件中分配了一個項目模板。如何使用MvvmCross fluent API將RecyclerView項目的TextView綁定到Android上其ViewModel的屬性?

<MvxRecyclerView 
    android:id="@+id/my_recycler_view" 
    local:MvxItemTemplate="@layout/item_recycler_view" /> 

視圖模型很簡單,它是由剛剛保存數據的RecyclerView顯示一個屬性:

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

一般來說,我喜歡用MvvmCross流利的API儘可能因爲隱式重構支持。 所以在我的活動,我綁定了MvxRecyclerView的屬性是這樣的:

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

到目前爲止好。現在,該項目模板佈局文件基本上只包含一個TextView

<LinearLayout> 
    <TextView 
     android:id="@+id/innerText" /> 
</LinearLayout> 

而且我ViewModelItem類看起來是這樣的:

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

我現在的問題是,如何和我在哪裏綁定TextView.Text財產使用流利的API的ViewModelItem.Title財產?

我知道,通過在項目模板佈局文件中提供MvxBind屬性,沒有流利的API很容易,但我更喜歡流利的API解決方案。

回答

10

從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<TextView>(Android.Resource.Id.Text1); 

     this.DelayBind(() => 
     { 
      var set = this.CreateBindingSet<MyViewHolder, ViewModelItem>(); 
      set.Bind(this.textView).To(x => x.Title); 
      set.Apply(); 
     }); 
    } 
} 

在你的活動創建適配器並將其添加到您的RecyclerView:

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

並結合您的項目到您的適配器的的ItemsSource:

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

有一點要注意,你可能想通過分配點擊命令到您的自定義'ViewHolder',否則任何綁定到ItemClick都不會有任何影響。在[這個stackoverflow答案]示例(http://stackoverflow.com/questions/42938112/mvxrecyclerview-fluent-api-binding#answer-43055796)。 – Plac3Hold3r

2

基於肯的回答,我創建了幾個支持類和擴展來概括項目綁定,並將它們與使用示例一起推送到github:

https://github.com/lauxjpn/MvxItemBinder

它可以讓你寫項目綁定類似如下:

var recyclerView = FindViewById<MvxRecyclerView>(Resource.Id.RecyclerView); 

var set = this.CreateBindingSet<MainActivity, MainViewModel>(); 
set.Bind(recyclerView) 
    .For(v => v.ItemsSource) 
    .To(vm => vm.Items); 
set.Apply(); 

recyclerView.BindItems<ItemViewModel>(this, (itemView, itemSet) => 
    itemSet.Bind(itemView.FindViewById<TextView>(Resource.Id.item_template)) 
     .For(v => v.Text) 
     .To(vm => vm.Title) 
); 

或者更短:

var recyclerView = FindViewById<MvxRecyclerView>(Resource.Id.RecyclerView); 

var set = this.CreateBindingSet<MainActivity, MainViewModel>(); 
set.Bind(recyclerView.BindItems<ItemViewModel>(this, (itemView, itemSet) => 
     itemSet.Bind(itemView.FindViewById<TextView>(Resource.Id.item_template)) 
      .For(v => v.Text) 
      .To(vm => vm.Title))) 
    .For(v => v.ItemsSource) 
    .To(vm => vm.Items); 
set.Apply(); 
相關問題