Frage

Kleines Problem mit meiner Android-Anwendung und ich weiß nicht, wie ich es mit MVVM Cross lösen kann.

Hier ist mein Modell

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

Mein ViewModel

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

}

Mein 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>
...

Und hier kommt mein Problem, das „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'}}"
          />
...

Der „Click“-Befehl namens „MyTest“ ist mit dem von MvxBindableListView angegebenen Element verknüpft.Mit anderen Worten: Klicken Sie auf die Suche nach einem Befehl „MyTest“ in meinem Modell „Article“ statt in meinem ViewModel.Wie kann ich dieses Verhalten ändern, um mein ViewModel „ArticleViewModel“ zu verknüpfen, das für mein MvxBindableListView verantwortlich ist?

Irgendwelche Vorschläge?

War es hilfreich?

Lösung

Ihre Analyse ist definitiv richtig, was die Stelle angeht, an der das Klickereignis eine Bindung eingehen möchte.

Im Allgemeinen verfolge ich zwei Ansätze:

  1. Verwenden Sie ItemClick für die Liste
  2. Verwenden Sie Click weiterhin, führen Sie jedoch eine Umleitung auf der ViewModel-Seite durch.

Also...1

Der Hauptmenü im Tutorial hat ein ViewModel ein bisschen wie:

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

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

Dies wird in Axml verwendet als:

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

Dieser Ansatz kann nur für ItemClick für das gesamte Listenelement durchgeführt werden – nicht für einzelne Unteransichten innerhalb der Listenelemente.


Oder...2

Da wir keine haben RelativeSource Bindungsanweisungen in mvx, diese Art der Umleitung kann im ViewModel/Model-Code erfolgen.

Dies kann erreicht werden, indem ein verhaltensaktivierter Wrapper des Model-Objekts anstelle des Model-Objekts selbst präsentiert wird – z. B.Verwendung einer 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; } } 
}

Ihr Axml müsste dann Bindungen verwenden wie:

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

Und

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

Ein Beispiel für diesen Ansatz ist das Conference-Beispiel, das verwendet WithCommand

Jedoch...Bitte beachten Sie, dass bei der Verwendung WithCommand<T> Wir haben ein Speicherleck entdeckt – im Grunde weigerte sich die GarbageCollection, die eingebetteten Dateien zu sammeln MvxRelayCommand - weshalb WithCommand<T> Ist IDisposable und warum BaseSessionListViewModel löscht die Liste und verwirft die WithCommand-Elemente, wenn Ansichten getrennt werden.


Update nach Kommentar:

Wenn Ihre Datenliste groß ist und Ihre Daten fest sind (Ihre Artikel sind Modelle ohne PropertyChanged) und Sie nicht den Aufwand für die Erstellung einer großen Liste auf sich nehmen möchten List<WrappedArticle> Dann könnte eine Möglichkeit darin bestehen, a zu verwenden WrappingList<T> Klasse.

Dies ist dem Ansatz im Microsoft-Code sehr ähnlich – z.bei der Virtualisierung von Listen in WP7/Silverlight - http://shawnoster.com/blog/post/Improving-ListBox-Performance-in-Silverlight-for-Windows-Phone-7-Data-Virtualization.aspx

Für Ihre Artikel könnte das sein:

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
}   
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top