MVVMCross在MvxBindableListView中更改ViewModel

我的Android应用程序的小问题,我不知道如何解决它与MVVM交叉。

这是我的模型

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

我的ViewModel

 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”的“Click”命令链接在由MvxBindableListView给出的项目上。 换句话说,在模型“文章”中单击search命令“MyTest”,而不是我的ViewModel。 我怎样才能改变这种行为,以链接我的ViewModel“ArticleViewModel”这是我的MvxBindableListView负责?

有什么build议么?

Solutions Collecting From Web of "MVVMCross在MvxBindableListView中更改ViewModel"

您的分析对于点击事件尝试绑定的位置是绝对正确的。

我通常采取两种方法:

  1. 使用项目点击列表
  2. 继续使用Click,但在ViewModel一侧做一些redirect。

所以…… 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

由于我们在mvx中没有任何RelativeSource绑定指令,因此可以在ViewModel / Model代码中完成此类redirect。

这可以通过呈现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的Conference示例

然而…请注意,当使用WithCommand<T>我们发现内存泄漏 – 基本上GarbageCollection拒绝收集embedded的MvxRelayCommand – 这就是为什么WithCommand<T>IDisposable ,为什么BaseSessionListViewModel清除列表并configurationWithCommand元素意见分离。


更新后的评论:

如果你的数据列表很大 – 而且你的数据是固定的(你的文章是没有PropertyChanged的模型),你不想承担创build一个大的List<WrappedArticle>的开销,那么解决这个问题的方法之一可能是使用WrappingList<T>类。

这与Microsoft代码中采用的方法非常类似 – 例如在WP7 / Silverlight中虚拟化列表中 – http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7 -数据- 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 }