MVVMCross cambiando ViewModel dentro de un MvxBindableListView

Pequeño problema con mi aplicación de Android y no sé cómo solucionarlo con MVVM Cross.

Aquí está mi modelo

public class Article { string Label{ get; set; } string Remark { get; set; } } 

Mi ViewModel

 public class ArticleViewModel: MvxViewModel { public List<Article> Articles; .... } 

Mi layout.axml …

  <LinearLayout android:layout_width="0dip" android:layout_weight="6" android:layout_height="fill_parent" android:orientation="vertical" android:id="@+id/layoutArticleList"> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/editSearch" android:text="" android:singleLine="True" android:selectAllOnFocus="true" android:capitalize="characters" android:drawableLeft="@drawable/ic_search_24" local:MvxBind="{'Text':{'Path':'Filter','Mode':'TwoWay'}}" /> <Mvx.MvxBindableListView android:id="@+id/listviewArticle" android:choiceMode="singleChoice" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" local:MvxItemTemplate="@layout/article_rowlayout" local:MvxBind="{'ItemsSource':{'Path':'Articles'}}" /> </LinearLayout> ... 

Y aquí viene mi problema, el "article_rowlayout"

 ... <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/blue"> <TextView android:id="@+id/rowArticleLabel" android:layout_width="0dip" android:layout_weight="14" android:layout_height="wrap_content" android:textSize="28dip" local:MvxBind="{'Text':{'Path':'Label'}}" /> <ImageButton android:src="@drawable/ic_modify" android:layout_width="0dip" android:layout_weight="1" android:layout_height="wrap_content" android:id="@+id/rowArticleButtonModify" android:background="@null" android:focusable="false" android:clickable="true" local:MvxBind="{'Click':{'Path':'MyTest'}}" /> ... 

El comando "Click" llamado "MyTest" está enlazado en el elemento dado por MvxBindableListView. En otras palabras, haga clic en Buscar un comando "MyTest" en mi modelo "Artículo", en lugar de mi ViewModel. ¿Cómo puedo cambiar ese comportamiento para vincular mi ViewModel "ArticleViewModel" que es responsable de mi MvxBindableListView?

¿Alguna sugerencia?

Su análisis es sin duda correcto sobre dónde está tratando de vincular el evento de clic.

Hay dos enfoques que generalmente tomo:

  1. Utilizar ItemClick en la lista
  2. Continuando utilizando Click pero hacer alguna redirección en el lado de ViewModel.

Así que … 1

El menú principal del tutorial tiene un ViewModel un poco como:

 public class MainMenuViewModel : MvxViewModel { public List<T> Items { get; set; } public IMvxCommand ShowItemCommand { get { return new MvxRelayCommand<T>((item) => /* do action with item */ ); } } } 

Esto se utiliza en axml como:

 <Mvx.MvxBindableListView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res/Tutorial.UI.Droid" android:layout_width="fill_parent" android:layout_height="fill_parent" local:MvxBind="{'ItemsSource':{'Path':'Items'},'ItemClick':{'Path':'ShowItemCommand'}}" local:MvxItemTemplate="@layout/listitem_viewmodel" /> 

Este enfoque solo se puede hacer para ItemClick en todo el elemento de la lista, no en subviews individuales dentro de los elementos de la lista.


O … 2

Dado que no tenemos instrucciones de vinculación de RelativeSource en mvx, este tipo de redirección se puede hacer en el código ViewModel / Model.

Esto puede hacerse presentando un contenedor activado por comportamiento del objeto Model en lugar del propio objeto Model – por ejemplo, usando una List<ActiveArticle> :

 public ActiveArticle { Article _article; ArticleViewModel _parent; public WrappedArticle(Article article, ArticleViewModel parent) { /* assignment */ } public IMvxCommand TheCommand { get { return MvxRelayCommand(() -> _parent.DoStuff(_article)); } } public Article TheArticle { get { return _article; } } } 

Tu axml tendría entonces que usar enlaces como:

  <TextView ... local:MvxBind="{'Text':{'Path':'TheArticle.Label'}}" /> 

y

  <ImageButton ... local:MvxBind="{'Click':{'Path':'TheCommand.MyTest'}}" /> 

Un ejemplo de este enfoque es la muestra de la Conferencia que utiliza WithCommand

Sin embargo … note que al usar WithCommand<T> descubrimos una fuga de memoria – básicamente la GarbageCollection se negó a recopilar el MvxRelayCommand incrustado – por lo que WithCommand<T> es IDisposable y por qué BaseSessionListViewModel borra la lista y dispone de los elementos WithCommand cuando Las vistas se desprenden.


Actualizar después del comentario:

Si su lista de datos es grande – y sus datos son fijos (sus artículos son modelos sin PropertyChanged) y no quiere incurrir en la sobrecarga de crear una List<WrappedArticle> grande List<WrappedArticle> entonces una manera alrededor de esto podría ser utilizar un WrappingList<T> clase.

Esto es muy similar al enfoque adoptado en el código de Microsoft – por ejemplo, en las listas de virtualización en WP7 / Silverlight – http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7 -Data-Virtualization.aspx

Para sus artículos esto podría ser:

 public class ArticleViewModel: MvxViewModel { public WrappingList<Article> Articles; // normal members... } public class Article { public string Label { get; set; } public string Remark { get; set; } } public class WrappingList<T> : IList<WrappingList<T>.Wrapped> { public class Wrapped { public IMvxCommand Command1 { get; set; } public IMvxCommand Command2 { get; set; } public IMvxCommand Command3 { get; set; } public IMvxCommand Command4 { get; set; } public T TheItem { get; set; } } private readonly List<T> _realList; private readonly Action<T>[] _realAction1; private readonly Action<T>[] _realAction2; private readonly Action<T>[] _realAction3; private readonly Action<T>[] _realAction4; public WrappingList(List<T> realList, Action<T> realAction) { _realList = realList; _realAction = realAction; } private Wrapped Wrap(T item) { return new Wrapped() { Command1 = new MvxRelayCommand(() => _realAction1(item)), Command2 = new MvxRelayCommand(() => _realAction2(item)), Command3 = new MvxRelayCommand(() => _realAction3(item)), Command4 = new MvxRelayCommand(() => _realAction4(item)), TheItem = item }; } #region Implementation of Key required methods public int Count { get { return _realList.Count; } } public Wrapped this[int index] { get { return Wrap(_realList[index]); } set { throw new NotImplementedException(); } } #endregion #region NonImplementation of other methods public IEnumerator<Wrapped> GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(Wrapped item) { throw new NotImplementedException(); } public void Clear() { throw new NotImplementedException(); } public bool Contains(Wrapped item) { throw new NotImplementedException(); } public void CopyTo(Wrapped[] array, int arrayIndex) { throw new NotImplementedException(); } public bool Remove(Wrapped item) { throw new NotImplementedException(); } public bool IsReadOnly { get; private set; } #endregion #region Implementation of IList<DateFilter> public int IndexOf(Wrapped item) { throw new NotImplementedException(); } public void Insert(int index, Wrapped item) { throw new NotImplementedException(); } public void RemoveAt(int index) { throw new NotImplementedException(); } #endregion } 
  • No puede convertir implícitamente tipo 'System.IO.Stream' a 'Java.IO.InputStream'
  • Cómo recibir URL con filtros de intenciones Xamarin
  • Administrador de SDK de Visual Studio 2013 Android no funciona
  • Estilizar un texto de edición de Android para que parezca un selector de lista desplegable / spinner
  • Comprobar la versión de Xamarin.Android mediante programación
  • Depuración de un dispositivo "remoto" Android con Xamarin?
  • ¿Es posible especificar dinámicamente el nombre del paquete durante la compilación?
  • MVVMCross Obtener SelectedItem de un MvxBindableListView
  • Cliente de red compartida / SMB
  • Mono para Android, obfuscación de código
  • (Android Xamarin) Obtener valor de cadena de recursos en lugar de int
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.