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
- No se pudo iniciar la aplicación.
- ¿Se ejecutará una aplicación con armeabi sólo en dispositivos armeabi-v7a?
- Diseño personalizado para DialogFragment OnCreateView vs. OnCreateDialog
- Error al crear el proyecto Xamarin.Android con Google Play Services
- Visual Studio 2015 - Xamarin - Android - Obtener "resource.id no contiene una definición para xxx" cuando intento hacer algo en el archivo .cs
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?
- Mono Android. Marco de pruebas unitarias
- Registrar ContentObserver en Application.OnCreate () Servicio VS
- Protección de bases de datos SQLite locales (aplicación Android)
- Mono para Android - ¿Cómo funciona?
- El gestos de deslizamiento de Android no es confiable
- ¿Cómo guardar una imagen en almacenamiento interno y luego mostrarla en otra actividad?
- Diálogo de búsqueda en Mono Android
- Xamarin android guardar archivo de texto
Su análisis es sin duda correcto sobre dónde está tratando de vincular el evento de clic.
Hay dos enfoques que generalmente tomo:
- Utilizar ItemClick en la lista
- 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 }
- Administrador de alarmas en android
- Calcular la relación de aspecto de la imagen de destino Transformar perspectiva