Pregunta

Pequeño problema con mi aplicación Android y no sé como solucionarlo con MVVM Cross.

Aqui esta mi modelo

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

Mi modelo de vista

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

}

Mi diseño.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>
...

Y aquí viene mi problema, el "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'}}"
          />
...

El comando "Hacer clic" llamado "MyTest" está vinculado al elemento proporcionado por MvxBindableListView.En otras palabras, haga clic en buscar un comando "MyTest" en mi modelo "Artículo", en lugar de mi ViewModel.¿Cómo puedo cambiar ese comportamiento para vincular mi ViewModel "ArticleViewModel" que es responsable de mi MvxBindableListView?

¿Alguna sugerencia?

¿Fue útil?

Solución

Su análisis es definitivamente correcto acerca de dónde intenta vincularse el evento de clic.

Generalmente adopto dos enfoques:

  1. Utilice ItemClick en la lista
  2. Continuar usando Click pero realizar alguna redirección en el lado de ViewModel.

Entonces...1

El Menú principal en el tutorial tiene un ViewModel un poco como:

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

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

Esto se usa en axml como:

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

Este enfoque solo se puede realizar para ItemClick en todo el elemento de la lista, no en subvistas individuales dentro de los elementos de la lista.


O...2

Como no tenemos ninguno RelativeSource instrucciones de enlace en mvx, este tipo de redirección se puede realizar en el código ViewModel/Model.

Esto se puede hacer presentando un contenedor habilitado para comportamiento del objeto Modelo en lugar del objeto Modelo en sí;usando 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; } } 
}

Su axml entonces tendría que usar enlaces como:

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

y

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

Un ejemplo de este enfoque es la muestra de la Conferencia que utiliza Con comando

Sin embargo...tenga en cuenta que al usar WithCommand<T> Descubrimos una pérdida de memoria: básicamente, GarbageCollection se negó a recopilar el contenido incrustado. MvxRelayCommand - por eso WithCommand<T> es IDisposable y por qué BaseSessionListViewModel borra la lista y elimina los elementos WithCommand cuando se separan las vistas.


Actualización después del comentario:

Si su lista de datos es grande y sus datos son fijos (sus artículos son modelos sin PropertyChanged) y no desea incurrir en la sobrecarga de crear una lista grande List<WrappedArticle> entonces una forma de evitar esto podría ser utilizar un WrappingList<T> clase.

Esto es muy similar al enfoque adoptado en el código de Microsoft, p.en virtualizar listas en WP7/Silverlight - http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7-Data-Virtualization.aspx

Para sus artículos esto podría ser:

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
}   
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top