8

私の 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 によって指定された項目にリンクされています。つまり、ViewModel ではなく、モデル「Article」でコマンド「MyTest」をクリックして検索します。MvxBindableListViewを担当するViewModel「ArticleViewModel」をリンクするために、その動作を変更するにはどうすればよいですか?

助言がありますか?

4

1 に答える 1

7

クリックイベントがバインドしようとしている場所についての分析は間違いなく正しいです。

私が一般的に取っている2つのアプローチがあります:

  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

RelativeSourcemvx にはバインド命令がないため、このタイプのリダイレクトは 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を使用する Conference サンプルです。

ただし...使用時にメモリリークが発見されたことに注意してくださいWithCommand<T>-基本的にGarbageCollectionは埋め込みの収集を拒否しましたMvxRelayCommand-これが理由WithCommand<T>IDisposableあり、ビューが切り離されたときにBaseSessionListViewModelがリストをクリアし、WithCommand要素を破棄する理由です。


コメント後の更新:

データ リストが大きく、データが固定されており (記事が PropertyChanged のないモデルである)、大きなものを作成するオーバーヘッドを発生させたくない場合、これを回避する 1 つの方法はクラスList<WrappedArticle>を使用することです。WrappingList<T>

これは、 Microsoftコードで採用されているアプローチと非常によく似ています。たとえば、WP7/Silverlight でリストを仮想化する場合などです。-データ仮想化.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
}   
于 2012-10-02T07:00:29.983 に答える