Question

Petit problème avec mon application Android et je ne sais pas comment le résoudre avec MVVM Cross.

Voici mon modèle

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

Mon modèle de vue

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

}

Ma mise en page.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>
...

Et voici mon problème, le "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'}}"
          />
...

La commande "Click" appelée "MyTest" est liée sur l'élément donné par MvxBindableListView.En d'autres termes, cliquez sur rechercher une commande "MyTest" dans mon modèle "Article", au lieu de mon ViewModel.Comment puis-je modifier ce comportement afin de lier mon ViewModel « ArticleViewModel » qui est responsable de mon MvxBindableListView ?

Aucune suggestion?

Était-ce utile?

La solution

Votre analyse est tout à fait correcte quant à l'endroit où l'événement de clic tente de se lier.

Il y a deux approches que j'adopte généralement :

  1. Utilisez ItemClick sur la liste
  2. Continuez à utiliser Click mais effectuez une redirection du côté de ViewModel.

Số 1

Le Menu principal dans le tutoriel a un ViewModel un peu comme :

public class MainMenuViewModel
    : MvxViewModel
{
    public List<T> Items { get; set; }

    public IMvxCommand ShowItemCommand
    {
        get
        {
            return new MvxRelayCommand<T>((item) => /* do action with item */ );
        }
    }
}

Ceci est utilisé dans axml comme :

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

Cette approche ne peut être appliquée que pour ItemClick sur l'ensemble de l'élément de liste, et non sur des sous-vues individuelles au sein des éléments de liste.


Ou...2

Puisque nous n'en avons pas RelativeSource instructions de liaison dans mvx, ce type de redirection peut être effectué dans le code ViewModel/Model.

Cela peut être fait en présentant un wrapper activé par le comportement de l'objet Model plutôt que de l'objet Model lui-même - par ex.utilisant un 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; } } 
}

Votre axml devra alors utiliser des liaisons telles que :

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

et

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

Un exemple de cette approche est l'échantillon de conférence qui utilise AvecCommand

Cependant...veuillez noter que lors de l'utilisation WithCommand<T> nous avons découvert une fuite de mémoire - en gros, GarbageCollection a refusé de collecter les fichiers intégrés MvxRelayCommand - c'est pourquoi WithCommand<T> est IDisposable et pourquoi BaseSessionListViewModel efface la liste et supprime les éléments WithCommand lorsque les vues sont détachées.


Mise à jour après commentaire :

Si votre liste de données est volumineuse et que vos données sont fixes (vos articles sont des modèles sans PropertyChanged) et que vous ne voulez pas supporter les frais liés à la création d'un grand List<WrappedArticle> alors une solution pourrait être d'utiliser un WrappingList<T> classe.

Ceci est très similaire à l'approche adoptée dans le code Microsoft - par ex.dans les listes de virtualisation dans WP7/Silverlight - http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7-Data-Virtualization.aspx

Pour vos articles, cela pourrait être :

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
}   
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top