Xamarin.Forms XAML Liste?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Du kannst ein ListView benutzen, an welches du eine ObservableCollection bindest.

Zunächst brauchst du eine Modelklasse, die die einzelnen Einträge beschreibt. Wenn jedes Item nur aus einer Zahl, einem String, o.ä. besteht, benötigst du natürlich keinen separaten Typ. Ich gehe hier aber einmal von einem benutzerdefinierten Fall aus.

public class Person
{
  public string FirstName { get; set; }

  public string LastName { get; set; }
}

Dazu wird ein ViewModel angelegt. Ein ViewModel dient der Aufbereitung der Daten für ein View. Dafür hält es hier eine ObservableCollection. Das ist ein Datencontainer, der Benachrichtigungen erstellt, sollten ihm Elemente hinzugefügt oder von ihm entfernt werden. Das ist für später nützlich, denn der Plan wäre, in der Anwendung direkt nur dieses Objekt zu verändern, um Zustandsänderungen im View zu bewirken.

public class PersonViewModel
{
  public PersonViewModel()
  {
    Persons = new ObservableCollection<Person>
    {
      new Person { FirstName = "John", LastName = "Lennon" },
      new Person { FirstName = "Ringo", LastName = "Starr" },
      new Person { FirstName = "Paul", LastName = "McCartney" },
      new Person { FirstName = "George", LastName = "Harrison" }
    };
  }

  public ObservableCollection<Person> Persons { get; set; }
}

Dafür wird die Liste (bzw. eigentlich das gesamte ViewModel) an das View gebunden.

Mein View geht davon aus, dass das Projekt Example heißt und der Standardnamespace ebenso. Es für deinen Fall anzupassen, dürfte kaum ein Problem darstellen.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:vm="clr-namespace:Example;assembly=Example"
  x:Class="Example.Persons"
  Title="Example">
  <ContentPage.BindingContext>
    <vm:PersonViewModel />
  </ContentPage.BindingContext>
  
  <StackLayout>
    <ListView ItemsSource="{Binding Persons}">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <StackLayout Orientation="Horizontal" Padding="5">
              <Label Text="{Binding FirstName}" TextColor="Blue" />
              <Label Text="{Binding LastName}" TextColor="Red" />
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </StackLayout>
</ContentPage>

Wichtig ist zunächst, dass die ViewModel-Bindung via BindingContext hergestellt wird. Im Prinzip legt das Programm automatisch im Hintergrund eine neue Instanz des ViewModels an und bindet diese an die View-Instanz.

Innerhalb eines StackLayouts wird die ListView kreiert und ihre Datenquelle an das ObservableCollection-Property gebunden. Das heißt, sie kreiert automatisch die notwendigen Itemcontainer, in denen die einzelnen Elemente der Persons-Liste eingetragen werden. Sollten folgend noch Personen hinzukommen oder wieder entfernt werden, bewirken die ausgeschickten Benachrichtigungen der ObservableCollection, dass sich das View selbstständig aktualisiert.

Da die einzelnen Listenelemente von Persons komplexe Objekte sind, bedarf es noch einer genaueren Beschreibung, wie sich ein einzelnes Item aufbauen soll. Andernfalls würde die ListView einfach nur für jedes Element die ToString-Methode aufrufen und du hättest mehrere Einträge, die Example.Person lauten.

Also wird das ItemTemplate definiert. In dem liegen hier einfach nur zwei Labels, die sich jeweils an die Properties der Person-Klasse binden.

Zum Hinzufügen kann man sich einen Button mitsamt Textfeldern gleich unter der ListView erstellen.

<StackLayout Orientation="Horizontal">
  <Entry Text="{Binding NewPersonFirstName}" />
  <Entry Text="{Binding NewPersonLastName}" />
  <Button Command="{Binding AddPerson}" Text="Add" />
</StackLayout>

Die Textfelder werden an neue Properties im ViewModel gehängt und der Button an einen Command. Ein Command ist ein Objekt, welches eine Methode ausführen kann (Execute-Delegate). Zusätzlich könnte man auch noch eine Bedingung anknüpfen, ob der Command überhaupt ausführbar ist (CanExecute-Predicate).

Die neuen Elemente im ViewModel:

public PersonViewModel()
{
  AddPerson = new Command(() =>
  {
    Persons.Add(new Person
    {
      FirstName = NewPersonFirstName,
      LastName = NewPersonLastName
    }
  });

  // ...
}

public ICommand AddPerson { get; }

public string NewPersonFirstName { get; set; }

public string NewPersonLastName { get; set; }

Bezüglich des Löschens von Einträgen würdest du es dir für den Anfang leichter machen, einfach jedes Item im ListView mit einem Button auszustatten.

<Button Command="{Binding RemovePerson}" CommandParameter="{Binding}" />

Dessen Command bekommt diesmal einen Parameter mit auf den Weg, welcher das Person-Objekt selbst darstellt. Das Command-Objekt ist diesmal generisch, ich zeige nur die Definition:

RemovePerson = new Command<Person>(person => Persons.Remove(person));

Lösungen, wie man einen langen Druck abfängt, kannst du dir wiederum von hier ziehen:

für diese Antwort empfände ich eine eigene Erklärung zu lang.

Generell solltest du die Microsoft Dokumentation als deine erste Quelle nutzen. In ihr findest du zahlreiche Artikel und auch Beispiele zu Xamarin (sei es zu einzelnen Komponenten, Bindings, Commands, etc.). Grundkenntnisse von C# und OOP werden natürlich wie immer vorausgesetzt. Hinzu kommt, wenn du meinem Lösungsweg folgst, das MVVM-Pattern.

DoGame5 
Fragesteller
 12.09.2021, 07:09

Vielen Dank das du immer bei mir antwortest und solche guten tutorials machst. Ich werde es dann gleich ausprobieren.

0