Was ist das MVVM-Muster?

Abgeschlossen

Xamarin.Forms-Apps ohne MVVM enthalten in der Regel mehr Code in den zugehörigen CodeBehind-Dateien. Die CodeBehind-Dateien folgen diesem Muster: {something}.xaml.cs. Der meiste Code in der CodeBehind-Datei steuert üblicherweise das Verhalten der Benutzeroberfläche (User Interface, UI). Das UI-Verhalten kann alle Ereignisse umfassen, die auf der Benutzeroberfläche stattfinden, z.B. die Änderung einer Farbe oder eine Textänderung. Darüber hinaus kann das Verhalten auch alle Ereignisse einschließen, die aufgrund der Benutzeroberfläche stattfinden, z. B. die Verwendung von Klickhandlern für Schaltflächen.

Ein Problem bei diesem Ansatz ist, dass es sehr schwierig ist, für CodeBehind-Dateien Unittests zu schreiben. CodeBehind-Dateien in einer Xamarin.Forms-App leiten sich aus einem Xamarin.Forms-Frameworktyp ab. Sie setzen häufig einen Anwendungsstatus voraus, der durch eine XAML-Analyse oder sogar durch andere Seiten erzeugt wird. Diese Bedingungen sind schwer zu berücksichtigen bei einem Test Runner für Unittests, der möglicherweise noch nicht einmal auf einem mobilen Gerät ausgeführt wird – geschweige denn mit einer Benutzeroberfläche. Über Komponententests kann also das Verhalten auf der Benutzeroberfläche in diesen Dateien selten getestet werden.

Bei richtiger Verwendung löst das MVVM-Muster diese Probleme, indem der Großteil der UI-Verhaltenslogik in Klassen (ViewModels genannt) verschoben wird, für die Unittests durchgeführt werden können. Das MVVM-Muster wird am häufigsten mit Frameworks eingesetzt, die die Datenbindung unterstützen. Dies liegt daran, dass Xamarin.Forms eine Datenbindung zwischen jedem UI-Element und einem ViewModel ermöglicht und so Code in einer View oder CodeBehind-Datei (fast vollständig) überflüssig macht.

Welche Bestandteile umfasst eine MVVM-Anwendung?

Neben dem ViewModel als bemerkenswertestem Bestandteil des MVVM-Musters definiert das Muster außerdem ein „Model“ und eine „View“. Die Definitionen dieser Elemente entsprechen denen einiger gängiger Muster, wie etwa dem Model-View-Controller (MVC).

Was ist ein Model?

In einer MVVM-Anwendung bezieht sich die Model-Komponente auf Ihre Geschäftsdaten und die Geschäftslogik. Die Model-Komponente hat nichts damit zu tun, wie die App dem Benutzer präsentiert wird.

Eine gute Richtlinie für die Definition des Codes im Model ist die, dass Sie Ihre Anwendung von der mobilen App auf das Web oder das Befehlszeilenprogramm portieren und in allen drei Fällen dasselbe Model verwenden können. Dies hat nichts mit der Darstellung für den Benutzer zu tun.

Im Hinblick auf die Anwendung für Personalabteilungen (HR) aus unserem Szenario kann die Model-Komponente eine Employee-Klasse und eine Department-Klasse umfassen, die Daten und Logik zu diesen Entitäten enthalten. Die Model-Komponente könnte zum Beispiel auch eine EmployeeRepository-Klasse enthalten, die Persistenzlogik umfasst. Einige andere Softwareentwurfsmuster würden Elemente wie Repositorys als vom Model getrennt betrachten. Aber im Kontext von MVVM beziehen wir uns häufig auf Geschäftslogik oder Geschäftsdaten als Teil des Models.

Hier zwei Beispiele für eine Model-Komponente in C#:

public class Employee
{
    public int Id { get; }
    public string Name { get; set; }
    public Employee Supervisor { get; set; }
    public DateTime HireDate { get; set; }
    public void ClockIn() { ... }
}

public class EmployeeRepository
{
    public IList<Employee> QueryEmployees() { ... }
    ...
}

Was ist eine View?

Der View-Code steuert Ereignisse, die mit einer direkten Interaktion mit dem Benutzer in Zusammenhang stehen. Üblicherweise sind dies Vorgänge wie das Ändern von Pixeln auf dem Bildschirm und das Empfangen von Klick- oder Tippereignissen. View-Elemente umfassen Steuerelemente wie Schaltflächen und Eingabefelder sowie rein visuelle Elemente wie Designs, Stile und Schriftarten.

Examples of views including controls (a button), colors/themes (a grid of colored squares), and fonts (a script typeface saying

In vielen Xamarin.Forms-Apps müssen Sie selbst keinerlei C#-Code für die View-Elemente schreiben. Stattdessen werden Ihre Views oft durch Ihre XAML-Dateien definiert. Es gibt natürlich Situationen, in denen ein benutzerdefiniertes Steuerelement aufgerufen wird. In diesen Fällen können Sie eigenen Code für die View schreiben. Informationen zum Erstellen benutzerdefinierter Xamarin.Forms-Steuerelemente finden Sie im Modul zum Xamarin.Forms-Renderer.

Was ist ein ViewModel?

Dies bringt uns zurück zur ViewModel-Komponente. Die ViewModel-Komponente ist der Vermittler zwischen der Geschäftslogik und den View-Elementen.

Diagram showing a ViewModel as an intermediary between a Model and View.

Bevor wir dies näher beleuchten, erfahren Sie, welche Aufgaben ein ViewModel-Element übernehmen kann. Ziehen wir dazu erneut das Beispiel der Anwendung für Personalabteilungen (HR) heran. Hier wird auf einer modalen Seite der verbleibende Urlaubsanspruch eines Mitarbeiters angezeigt. Auf dem Bildschirm soll das Urlaubsguthaben als Zeichenfolge im Format „2 Wochen, 3 Tage, 4 Stunden“ angezeigt werden. Unsere Geschäftslogik berechnet jedoch den gleichen Wert: 13,5 Tage. Unsere Struktur kann in etwa so aussehen:

  • Model: Die Employee-Klasse, die eine Methode umfasst:

    public decimal GetVacationBalanceInDays()
    {
        //Some math that calculates current vacation balance.
        ...
    }
    
  • ViewModel: Eine EmployeeViewModel-Klasse mit einer Eigenschaft wie dieser:

    public class EmployeeViewModel
    {
        private Employee _model;
        ...
        public string FormattedVacationBalance
        {
            get
            {
                decimal vacationBalance = _model.GetVacationBalanceInDays();
                ... // Some logic to format and return the string
            }
        }
    }
    
  • View: Eine XAML-Seite, die eine einzige Beschriftung und eine Schaltfläche zum Schließen enthält. Die Beschriftung umfasst eine Bindung zu unserer ViewModel-Eigenschaft:

    <Label Text="{Binding FormattedVacationBalance}" />
    

    Anschließend muss nur noch das BindingContext-Objekt für die Seite auf eine Instanz von EmployeeViewModel festgelegt werden.

In diesem Beispiel übernimmt unser Model die Geschäftslogik. Diese Logik ist nicht an Xamarin.Forms oder an die mobile App oder noch nicht einmal an ein visuelles Display gebunden. Sie könnten dieselbe Logik auch für eine Telefonieanwendung verwenden. Die View besitzt keinerlei Kenntnis über die Geschäftslogik. Beschriftungen können Pixel auf einem Bildschirm platzieren, aber hierbei ist es vollkommen unwichtig, ob Sie einen Urlaubsanspruch oder eine zufällige Zeichenfolge anzeigen. Das ViewModel besitzt ein wenig Kenntnis beider Welten, sodass es als Vermittler fungieren kann.

Das Interessante am ViewModel ist, wie es seine Vermittlerrolle erfüllt: Es macht Eigenschaften verfügbar, an die die View gebunden werden kann. Öffentliche Eigenschaften sind die einzige Möglichkeit, durch die ein ViewModel Daten bereitstellen kann. Das wirft die Frage auf, warum es „Ansichtsmodell“ heißt. Während das Model im MVVM-Muster die Struktur, Daten und Logik der Geschäftsprozesse repräsentiert, stellt das Ansichtsmodell (ViewModel) die Struktur, Daten und Logik dar, die von der Ansicht benötigt werden.