MVVM C#
Inhaltsverzeichnis
MVVM C#
Du möchtest mit MVVM in C# durchstarten und somit deine Anwendungen durch das „Model View ViewModel„-Entwurfsmuster auf ein neues Level bringen?
Oder möchtest Du verstehen, was dieses Entwurfsmuster ist, warum man es verwendet und vor allem wie man es in C# anwendet – dann los!
Vielleicht hast Du in Kombination mit diesem Beitrag auch noch Interesse an diesen anderen Beiträgen: ObservableCollection, WPF DataTemplate, MahApps Metro Framework.
Die alten Zeiten
Die alten Zeiten glänzten vor Misch-Masch, vor allem wenn es um Daten und deren Darstellung in Steuerelementen ging. Als Entwickler – für gewöhnlich mit der Entwicklung von Prozessen und deren Testung beschäftigt – hatte man sich auch mit der grafischen Oberfläche auseinanderzusetzen.
Dies hatte häufig eine schlechte Wart- und Testbarkeit zur Folge und somit eine Vermischung der Rollen. Während die Designer Ihr Augenmerk auf UI/UX und die Entwickler Ihren Fokus auf die Logik legen sollten, waren diese Rollen stattdessen fließend.
Du wirst diese Problematik nachvollziehen können, wenn Du selbst einmal mehrere Rollen gleichzeitig ausfüllen musstest. Vor allem in kleinen Firmen ist häufig aufgrund des Budgets nicht die Manpower vorhanden, um einzelne Bereiche separat abzudecken.
Das hat dann leider zwangsweise zur Folge, dass diese Bereiche und deren Verantwortlichkeiten nicht sauber getrennt werden. Ein jeweiliges Team muss somit die individuellen Stärken in den Hintergrund stecken und einzelne Rollen aus dem Fokus verlieren.
MVVM das Optimum – Jedem das Seine
Ich denke, jedem sollte seine Rolle überlassen werden, damit er sich voll und ganz darauf konzentrieren und seine Stärken ausspielen kann.
Das MVVM-Entwurfsmuster bietet eine tolle Basis für die Umsetzung separater Bereiche durch eigene Teams. Datenbank–Designer können sich auf die Modellierung konzentrieren, Schnittstellen–Entwickler auf ihre Schnittstellen und DTOs.
Weitere Entwickler setzen den Fokus auf ihre Business-Logik und die Designer letztendlich auf Ihre grafische Oberfläche. Natürlich gibt es auch noch weitere Bereiche, Welche besonders in kleinen Firmen vermischt werden, aber tauchen wir nicht zu tief darin ab.
MVVM erklärt – MVVM C#
Bevor wir nun den Bezug zu C# konkretisieren, beschäftigen wir uns noch näher mit den Details des MVVM-Entwurfsmusters. Schaue Dir ggf. zeitgleich zu den Erklärungen noch folgendes Bild in z. B. einem zusätzlichen Tab an:
View
Den ersten Block auf den Du oben im Bild stoßen wirst, ist das View. Es spiegelt einzelne visuelle Bestandteile wie eine Sidebar oder auch Kacheln wider und kombiniert Diese in logischer/schöner Form. Denke jedoch bei einem View bitte nicht zwangsweise an ein stupides Fenster.
Auch wenn ein Fenster sicherlich eine Art von View ist, ist es nicht „das Eine“ View schlechthin. Vielen sich noch nicht lange mit dem MVVM-Pattern beschäftigenden Menschen, kommt bei dem Gedanken an ein „View“, automatisch sowas wie Programm–„Fenster“ in den Sinn.
Sicher ist das typische Fenster ein Anfang, jedoch könnte man es genauso gut in weitere Sub-Views und Sub-ViewModels unterteilen. Diese können dann entweder direkt, oder indirekt miteinander kommunizieren, bzw. interagieren.
Im Grunde ist das View eine Art „Template„, Welches nur die benötigten Anweisungen für die Datenbindungen bekommt. Somit hat es alle notwendigen Informationen, um die durch Templates bestimmte Elemente anhand der Daten darzustellen.
Die Datenbindungen bestimmen z. B. auch im ViewModel vorgesehene Methoden, die z. B. bei Klicks von Buttons aufgerufen werden sollen.
ViewModel
Das ViewModel beinhaltet die aufbereiteten Daten, die dem View durch Datenbindungen zur Verfügung gestellt werden.
Dem ViewModel werden über diverse Techniken wie die Dependency-Injection, Services und mehr injiziert, Welche das ViewModel dann verwenden kann. Über diese Services kann das VM dann diverse Daten/Models laden und anschließend nach eigener Logik aufbereiten.
Wie oben schon erwähnt beinhaltet das ViewModel auch die für die Buttons relevanten Methoden.
Zusätzlich dazu, kann ein ViewModel gewiss auch eigene Ereignisse auslösen und auch auf abonnierte Ereignisse reagieren. Somit hast Du nun auch schon einen möglichen Weg kennengelernt, wie ViewModels untereinander kommunizieren können.
Ein alternativer Weg zu dieser Kommunikationsweise wäre die Verwendung eines EventBus. Dieser Weg funktioniert zwar auch mit einer Art Ereignissen, jedoch ein wenig anders. Eventuell tauchen wir in diesem Beitrag noch tiefer in die Materie des EventBus, allerdings dürfte das vermutlich den Rahmen sprengen.
Model
Das Model im MVVM-Entwurfsmuster stellt häufig die Daten ,mit denen man arbeitet dar. Wenn Du zum Beispiel einen Terminkalender programmierst, wäre das Erste, was einem dazu wohl einfällt der Termin selbst. Du würdest Dir Gedanken machen, welche Eigenschaften wie z. B.: Betreff, Startdatum, usw. der Termin hat.
Danach würdest Du vermutlich hingehen und Dir eine Klasse wie Diese hier bauen:
Public Class Appointment Public Property Subject As String Public Property StartDate As Date Public Property Priority As Priority End Class
public class Appointment { public string Subject { get; set; } public DateTime StartDate { get; set; } public Priority Priority { get;set; } }
Hier ist die zum Termin gehörige Enumeration der Prioritäten, nur als kurzes Beispiel:
Public Enum Priority As Byte NORMAL HIGH VERY_HIGH End Enum
public enum Priority : byte { NORMAL, HIGH, VERY_HIGH }
Vorteile von MVVM
Wie Du oben schon lesen konntest, bringt dass MVVM-Entwurfsmuster einige Vorteile mit sich. Welche Vorteile das genauer genommen sind, werden wir uns nun noch einmal separat ansehen.
Trennung von Daten und deren Darstellung
Das Gotcha dieser Herangehensweise mag vielleicht nicht immer auf ersten Blick erkennbar sein. Lass es mich Dir daher so erklären: Eine saubere Trennung, also die Unabhängigkeit von Dingen, gibt Diesen immer eine Möglichkeit, getrennt voneinander zu wachsen.
Auf unser Beispiel in der Softwareentwicklung bezogen, bedeutet das natürlich einen Vorteil in den Bereichen: Aufwand, Wartbarkeit, Austauschbarkeit und mehr.
Darstellungsmöglichkeiten
Stelle Dir vor, dein Termin–Model hat ein Start– und ein Enddatum, Welche Du in verschiedenen Views ggf. unterschiedlich darstellen möchtest. Für einen Termin im Kalender selbst, spielen die Sekunden ggf. keine Rolle, bei einer Abrechnung für einen größeren Zeitraum allerdings schon!
Würdest Du dann dein Model „verschmutzen“ wollen, indem Du für 3 unterschiedliche Verwendungsfälle 3 unterschiedliche neue Eigenschaften hinzufügst? Ich würde lieber das Model unangetastet lassen und das jeweilige ViewModel die Daten aufbereitet darstellen lassen!
Aggregation von Daten
Leider kommt es eher selten vor, dass Du die benötigten Daten in jener Kombination hast, wie Du sie tatsächlich brauchst. Unterschiedliche Views, Anwendungsfälle, Herausforderungen benötigen auch nun einmal meist unterschiedliche „Vorbereitung„.
Daher hat man durch die Verwendung von ViewModels die Möglichkeit, Models zu aggregieren, bzw. zu kombinieren.
Zwei-Wege Bindungen & Code-Duplikate
Ein weiterer mir sofort einfallender Vorteil ist die Zwei-Wege Datenbindung, womit man sich teils nervige Aufrufe wie „DeinControl.Text = ..“ spart. Pardon, aber Gott habe ich das bei Windows Forms (Winforms) teilweise gehasst. Immer dieses Hin und Her mit den Daten..
Die geänderten Daten werden durch die Bindung direkt von der Quelle zum Ziel und umgekehrt weitergeleitet. Das spart nicht zur Zeit, sondern ich empfinde dies persönlich auch als wesentlich sauberer. Wenn man dann noch Hilfsmittel wie „Fody“ verwendet, muss man sich auch nicht um die „INotifyPropertyChanged„-Schnittstelle kümmern – auch dazu ggf. später mehr.
Testbarkeit
Aufgrund der sauberen Trennung von Daten und Oberfläche, ist es relativ leicht, ein ViewModel mit verschiedenen Views zu testen. Dies gilt natürlich auch andersherum, es hindert mich keiner daran, das gleiche View mit einem anderen ViewModel zu testen. Das ist unter Anderem die vorhin schonmal angesprochene Austauschbarkeit – cool, oder!?
Ebenso können die ViewModels in Test-Umgebungen völlig autark getestet und teils ohne Oberflächen überprüft werden. Das kann viel „repetitive work“ verhindern und auch viele Prozesse automatisieren. Es läuft schlicht simpler von der Hand und muss „nur“ gecodet werden.
Support in .NET
Der MVVM–Support in .NET ist durch viele bereitgestellte Schnittstellen wie z. B. „INotifyPropertyChanged“ und „INotifyCollectionChanged“ grandios. Natürlich bietet das .NET Framework auch bereits „ready-to-use„-Implementierungen für diverse Schnittstellen an.
Von vielen Außenstehenden wird WPF hoch gelobt und auch wenn ich damals selbst sehr zögerlich an die Sache ging. Die Zeit die ich bisher mit WPF verbracht habe, hat mich definitiv zur Meinung gebracht, nie wieder ohne arbeiten zu wollen. WPF ist einfach besser: schneller, stylischer, fehlerfreier (starte heuzutage mal eine Winforms Anwendung im Visual Studio und arbeite 2 Wochen, gar 2 Tage damit..) – irgendeinen Bug wirst Du sicherlich sehen…
Styling
Es macht auch einen riesen Spaß, einfach ViewModel-Daten an spezifische Stile zu binden und das Look-And-Feel der Anwendung darüber zu gestalten. Wieder beim Beispiel Termine angekommen, könnte man hier einfach je nach Priorität einen Termin kinderleicht anders färben. Dazu bauen wir uns schnell etwas Passendes Beispiel zurecht und sehen schnelle Ergebnisse.
MVVM C# Beispiel
Einen beispielhaften Termin mit Priorität „Normal“ stelle ich zum Beispiel im nächsten Bild einmal dar:
Wenn ich die Priorität des Termins nun im Code ändere, wird das Label beim nächsten Start anders dargestellt:
Normalerweise würde man das hier – statt erst nach Programmstart – natürlich auch via Datenbindung + Änderungs–Benachrichtigung bauen. Ich wollte es für das Beispiel allerdings so einfach wie möglich halten!
Man könnte selbstverständlich auch noch wesentlich tiefer in die Materie eindringen, allerdings denke ich, dass dieses Beispiel erstmal reicht. Du hast hier letztendlich Daten, die sich im Hintergrund befinden und durch „Regeln“ im View unterschiedlich dargestellt werden. Dafür nutzen wir ein ViewModel, was die Datenquelle des MainWindows wird und instanziieren dort eine Instanz des Termin-Models.
Basierend auf der Priorität hätte man auch die Möglichkeit, völlig verschiedene Templates zu wählen, aber das wird ein späteres Thema sein.
Fazit
MVVM ist also ein sogenanntes Entwurfsmuster für Anwendungen, um Diese besser managen zu können. Von der Rollenverteilung der involvierten Mitarbeiter, bis hin zu Testbarkeit und mehr, lässt sich dadurch vieles besser gestalten.
Wie Du sehen konntest handelte es sich in diesem Beitrag erstmal um das Grundverständnis von MVVM allgemein. Sorry, falls wir also nur erstmal eine kleine Oberfläche von WPF angekratzt haben.
Sicherlich werde ich in Zukunft auch noch weitere und vor allem detailliertere Beispiele demonstrieren. Diese wirst Du dann in Form von konkreten Einsatzmöglichkeiten und Mini–Projekten in anderen Beiträgen finden.