MVVMCross改变视图模型一个MvxBindableListView内视图、模型、MVVMCross、MvxBindableListView

2023-09-12 01:21:41 作者:微笑式凋谢

小问题,我的Andr​​oid应用程序,我不知道如何与MVVM跨解决它。

Little problem with my Android application and I don't know how to solve it with MVVM Cross.

下面是我的模型

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

我的视图模型

My ViewModel

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

}

我的layout.axml     ......

My 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

And here comes my problem, the "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的在我的模型文章。我怎样才能改变这种行为,以链接到我的视图模型ArticleViewModel这是负责我MvxBindableListView的?

The "Click" command called "MyTest" is linked on the item given by the MvxBindableListView. In other words, Click search for a command "MyTest" in my model "Article", instead of my ViewModel. How can I change that behaviour in order to link my ViewModel "ArticleViewModel" which is responsible of my MvxBindableListView?

有什么建议?

雨果

推荐答案

您的分析是完全正确在哪里click事件是在尝试绑定。

Your analysis is definitely correct about where the click event is trying to bind.

有两种方法我一般取:

使用项目单击上的列表 在使用点击,但做一些重定向的视图模型一边继续。

所以... 1

的Main在本教程菜单有一个视图模型有点像:

The Main Menu in the tutorial has a ViewModel a bit like:

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

此方法只能用于项目单击完成对整个列表项 - 不在名单上的项目中的各个子视图

This approach can only be done for ItemClick on the whole list item - not on individual subviews within the list items.

还是... 2

由于我们没有在MVX任何的RelativeSource 约束力的指示,这种类型的重定向可以在视图模型/型号code完成的。

Since we don't have any RelativeSource binding instructions in mvx, this type of redirection can be done in the ViewModel/Model code.

这可以通过$ P $完成psenting Model对象的激活行为包装而不是模型对象本身 - 例如,使用名单,其中,ActiveArticle&GT;

This can be done by presenting a behaviour-enabled wrapper of the Model object rather than the Model object itself - e.g. using a 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将不得不使用类似的绑定:

Your axml would then have to use bindings like:

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

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

这种方法的一个例子是会议的样品,它使用WithCommand

不过......请注意,如果使用 WithCommand&LT; T&GT; 我们发现了一个内存泄漏 - 基本上是垃圾回收拒绝收集嵌入 MvxRelayCommand - 这也就是为什么 WithCommand&LT; T&GT; 的IDisposable 为什么BaseSessionListViewModel清除列表并配置WithCommand元素时,视图分离。

However... please note that when using WithCommand<T> we discovered a memory leak - basically the GarbageCollection refused to collect the embedded MvxRelayCommand - which is why WithCommand<T> is IDisposable and why BaseSessionListViewModel clears the list and disposes the WithCommand elements when views are detached.

注释后的更新:

如果您的数据列表很大 - 和你的数据是固定的(你的文章是型号没有的PropertyChanged),你不希望发生创建一个大的名单,其中的开销; WrappedArticle&GT; 然后围绕这一个办法可能是使用一个 WrappingList&LT; T&GT;

If your data list is large - and your data is fixed (your articles are models without PropertyChanged) and you don't want to incur the overhead of creating a large List<WrappedArticle> then one way around this might be to use a WrappingList<T> class.

这是非常类似于Microsoft code所采取的办法 - 如在WP7 / Silverlight的虚拟化名单 - http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7-Data-Virtualization.aspx

This is very similar to the approach taken in Microsoft code - e.g. in virtualizing lists in WP7/Silverlight - http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7-Data-Virtualization.aspx

有关你的文章,这可能是:

For your articles this might be:

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
}