Intereting Posts
Синхронизировать / обновлять базы данных sqlite Как сохранить каждую позицию страницы просмотра в списке из них? Retrofit2, отправляющий метод запроса PUT, неверен для PHP Как сделать макет кликабельным программным путем Как использовать ddms для утечек памяти в c ++-коде Любой совместный инструмент / веб-сайт для локализации приложения для Android? Как избежать того, что мое приложение внедряет оптимизацию на устройствах Samsung Как имитировать пользователя, нажмите на элемент списка в тестировании юнита? AppCompatSpinner vs android.widget.Spinner для приложения с минимальным SDK версии 14 Распознавание изображений для приложения дополненной реальности Android Поведение кнопки Android назад Аудио Воспроизведение из URI Inside Listview, но Seekbar не обновляется в элементе списка ListView Как сохранить выделение выделенного элемента в gridview при изменении numColumns? Как обновить Android Studio автоматически? Импорт com.google.android.vending не может быть разрешен в импортированном проекте Android

MVVMCross меняет ViewModel в MvxBindableListView

Маленькая проблема с моим Android-приложением, и я не знаю, как ее решить с помощью MVVM Cross.

Вот моя модель

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

Моя модель просмотра

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

Мой 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> ... 

И вот моя проблема, «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'}}" /> ... 

Команда «Щелчок» под названием «MyTest» связана с элементом, заданным MvxBindableListView. Другими словами, нажмите «Поиск» команды «MyTest» в моей модели «Article» вместо моей ViewModel. Как я могу изменить это поведение, чтобы связать мой ViewModel «ArticleViewModel», который отвечает за мой MvxBindableListView?

Какие-либо предложения?

Ваш анализ определенно корректен в отношении того, где пытается связать событие click.

Есть два подхода, которые я обычно делаю:

  1. Использовать ItemClick в списке
  2. Продолжая использование Click, но сделайте некоторое перенаправление на стороне ViewModel.

Таким образом, 1

Главное меню в учебнике имеет ViewModel немного похоже на:

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

Это используется в axml как:

 <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" /> 

Этот подход может быть сделан только для ItemClick во всем элементе списка – не для отдельных подзонов в элементах списка.


Или … 2

Поскольку у нас нет инструкций по привязке RelativeSource в mvx, этот тип перенаправления может быть выполнен в коде ViewModel / Model.

Это можно сделать, представив оболочку с включенным поведением объекта Model, а не сам объект Model – например, используя 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; } } } 

Затем ваш axml должен будет использовать привязки, такие как:

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

а также

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

Одним из примеров такого подхода является образец Конференции, в котором используется WithCommand

Однако … обратите внимание, что при использовании WithCommand<T> мы обнаружили утечку памяти – в основном GarbageCollection отказался собирать встроенный MvxRelayCommand – вот почему WithCommand<T> является IDisposable и почему BaseSessionListViewModel очищает список и использует элементы WithCommand, когда Вид снят.


Обновление после комментария:

Если ваш список данных является большим – и ваши данные фиксированы (ваши статьи являются моделями без PropertyChanged), и вы не хотите List<WrappedArticle> накладные расходы на создание большого List<WrappedArticle> то одним из способов может быть использование WrappingList<T> .

Это очень похоже на подход, используемый в коде Microsoft – например, в виртуализации списков в WP7 / Silverlight – http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7 -Data-Virtualization.aspx

Для ваших статей это может быть:

 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 }