¿Cómo usar la API fluida de MvvmCross para enlazar TextView de un elemento de RecyclerView a una propiedad de su ViewModel en Android?
Estoy utilizando MvvmCross en mi proyecto Xamarin Android . Tengo un MvxActivity
con un MvxRecyclerView
, que he asignado una plantilla del artículo en su archivo de la disposición.
<MvxRecyclerView android:id="@+id/my_recycler_view" local:MvxItemTemplate="@layout/item_recycler_view" />
El ViewModel es bastante simple, consiste sólo de una propiedad que contiene los datos para mostrar en el RecyclerView
:
- ¿Cuáles son las ventajas de RecyclerView en comparación con ListView?
- Tarjeta de material con la biblioteca Cardslib
- Recycleview en el conjunto de coordenadas
- PopupMenu no se encuentra correctamente dentro de RecyclerView
- ¿No puede actualizar RecyclerView desde mi clase de modelo?
public class MainViewModel : MvxViewModel { private IEnumerable<ViewModelItem> _viewModelItems; public IEnumerable<ViewModelItem> ViewModelItems { get { return _viewModelItems; } set { SetProperty(ref _viewModelItems, value); } } }
En general, me gusta usar el fluido MvvmCross API tanto como sea posible debido a la implícita Refactoring apoyo. Así que en mi actividad, estoy vinculando una propiedad de MvxRecyclerView
como esto:
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();
Hasta aquí todo bien. Ahora, el archivo de diseño para la plantilla de elemento básicamente sólo contiene un TextView
:
<LinearLayout> <TextView android:id="@+id/innerText" /> </LinearLayout>
Y mi clase ViewModelItem
ve así:
public class ViewModelItem { public string Title { get; set; } }
Mi pregunta ahora es, ¿cómo y dónde enlazar la propiedad TextView.Text
a la propiedad ViewModelItem.Title
utilizando la fluida API?
Sé que es bastante fácil de hacer sin la API fluida al proporcionar un atributo MvxBind
en el archivo de diseño de la plantilla de elementos, pero realmente prefiero una solución API fluida.
- Comportamiento extraño de RecyclerView después de eliminar el elemento
- Span múltiples columnas con RecyclerView
- Diseño como la aplicación HotStar
- Android: Añadir divisor entre los elementos de RecyclerView
- Recyclerviews en ViewPager
- ¿Hay observadores escritos en RecyclerView.Adapter para saber si el conjunto de datos ha sido cambiado?
- RecyclerView Adapter da error "La jerarquía del tipo RecycleAdapter es inconsistente"
- RecyclerView notifyItemRangeChanged no muestra nuevos datos
Heredar de MvxRecyclerAdapter y crear un adaptador personalizado para su RecyclerView. Anular OnCreateViewHolder
y devolver un ViewHolder personalizado.
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); } }
Dentro de este ViewHolder puede utilizar el Fluent API para la encuadernación.
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(); }); } }
En su actividad, cree el adaptador y agréguelo a su RecyclerView:
var adapter = new MyAdapter((IMvxAndroidBindingContext)this.BindingContext); recyclerView.Adapter = adapter;
Y enlazar sus artículos a ItemsSource de su adaptador:
set.Bind(this.adapter).For(x => x.ItemsSource).To(x => x.ViewModelItems);
Sobre la base de la respuesta de Ken, he creado un par de clases de soporte y extensiones para generalizar la vinculación de los elementos y los empujó junto con una muestra de uso de github:
https://github.com/lauxjpn/MvxItemBinder
Le permite escribir enlaces de artículos como los siguientes:
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) );
O incluso más corto:
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();