Meine neue WebSite finden Du jetzt unter https://AttilaKrick.com.
Siehe auch: MSDN – Implementing the MVVM Pattern
MVVM (Model View ViewModel) ist ein Programm-Entwurfsmuster zur Entkoppelung von Markup und Logik der UI. Es sieht die Rollentrennung von UI-Designern (VIEW) und Entwicklern (MODEL und VIEWMODEL) vor.
Vorteile: Durch diese Trennung können die Anwendungsschichten von verschiedenen Arbeitsgruppen entwickelt werden. Designer können einen Fokus auf das Benutzererlebnis und die UI legen (VIEW) und Entwickler unabhängig davon die UI- und Geschäftslogik schreibe (MODEL und VIEWMODEL). In der Regel sind keine aufwendigen UI-Tests nötig. Stattdessen genügen codebasierte Modul-Tests des ViewModel. Auch ist eine leichtere Austauschbarkeit der View z.B. nach WPF oder Windows Phone möglich. Unterstützung in WPF, Silverlight, Windows Phone und Windows Store Apps.
Nachteil: MVVM stellt einen Mehraufwand dar und ist für Anwendungen mit einfacher UI ein Overkill. Für größere Anwendungen kann das Design eines ausreichend allgemeinen ViewModel’s im Voraus schwierig sein. Außerdem führe eine schlecht verwaltete Datenbindung zu einem erheblichen Speicherbedarf der Anwendung.
Das MVVM-Entwurfsmuster besteht aus den folgenden Schichten und Kern-Technologien:
View : XAML, UX-Logik, Bindung zum ViewModel/Model und der Datenkonvertierung über IValueConverter
ViewModel : Stellt Bindbare Propertys und Commands bereit und enthält UI-Logik. Hierfür stehen folgende Komponenten zur Verfügung:
ICommand
, INotifyPropertyChanged
, NotifyCollectionChanged
, INotifyCollectionChanged
und INotifyDataErrorInfo
.
Model : Entität, Geschäftsregeln und Validierungs-Logik. Hierfür stehen folgende Komponenten zur Verfügung:
ObservableCollection<T>
, INotifyPropertyChanged
, INotifyCollectionChanged
, und INotifyDataErrorInfo
.
[Data|View|Etc.]Services : Diverse Dienste die MVVM zuarbeiten und auf verschiedenen Plattformen unterschiedlich implementiert werden. Zum Beispiel der Zugriff auf unterschiedliche Datenbank-Hersteller oder die Implementierung der MessageBox in Apps, WPF oder auf einem Windows Phone.
DataService
Die DataService-Schicht übernimmt die Aufgabe der Datenbeschaffung (GetAllKunden()) bzw. der Datenaktualisierung (UpdateKunde(kunde)).
Die DataAccess-Schicht wird Ausgeführt im Model oder im ViewModel.
In einfachen Anwendungen schließt das Model diesen Code zur Unterstützung von Datenzugriff und Caching mit ein.
Stehen unterschiedliche Daten-Anbieter (DB, XML, WCF, etc.) zur Verfügung kann die Aufgaben der Datenbereitstellung aus dieser Schicht entkoppelt und in eine eigene ProviderService-Klasse implementiert werden. Diese ProviderService’s sollten ein zuvor erstelltes Interface (z.B. IProviderService) implementieren um Provider-Unabhängig im DataService Daten beschaffen zu können:
/* ZUM BEISPIEL
DataService ds;
ds = new DataService(new WCFProviderService()); // If Online
ds = new DataService(new DBProviderService()); // else Offline
*/
public interface IProviderService {
object GetKunden();
}
public class DBProviderService : IProviderService {
public object GetKunden() {
return "Geladene Kunden von der DB";
}
}
public class WCFProviderService : IProviderService {
public object GetKunden() {
return "Geladene Kunden vom HTTPS-WCF-Dienst";
}
}
public class DataService {
public DataService(IProviderService providerService) {
ProviderService = providerService;
}
IProviderService ProviderService;
public object GetKunden() {
var kunden = ProviderService.GetKunden();
// Aufbereiten der Kunden
return kunden;
}
}
Model
Das Model ist für die Verwaltung, Konsistenz und Gültigkeit der enthaltenen Entitäten verantwortlich.
Das Model besteht aus:
Gekapselter Entität und deren Daten
Geschäftsregeln
Validierungs-Logik
Eine Anwendungs-Domäne besteht aus mehreren Model’s der Geschäftsentität, aus Auflistungen von Geschäftsentitäten oder aus Kombinationen beider.
Bei einfacher DataService-Schicht kann diese Aufgabe direkt im Model implementiert werden.
Das Model ist eine nicht-visuelle Klasse die weder von einer visuellen Klasse abgeleitet wird noch visuelle Objekte implementiert.
Das Model besitzt keine Referenz oder Abhängigkeit zum ViewModel oder zur View.
Wenn Ihre Anwendungs-Domäne aus mehreren Model’s besteht empfiehlt es sich die benötigten Interfaces in einer abstrakten Klasse ModelBase zu implementieren und von dieser zu erben.
Das Model könnte auch in einem WCF-Dienst implementiert sein was das ViewModel anschließend konsumiert.
Für Benachrichtigung über Eigenschaftsänderungen implementiert das Model INotifyPropertyChanged
bzw. INotifyCollectionChanged
. Diese Benachrichtigungen benötigt ViewModel/View um ihre Daten/Anzeige zu aktualisieren. Diese Benachrichtigungsdienst kann auch vom ViewModel übernommen werden.
Auflistungen von Objekten die später an die View gebunden werden sollen, werden i.d.R. von ObservableCollection<T>
erstellt da diese Klasse u.a. INotifyCollectionChanged implementiert.
Validierung : Für die Datenüberprüfung und Fehlerberichterstattung wird INotifyDataErrorInfo
im Model implementiert oder diese Aufgabe übernimmt auch das ViewModel.
ViewModel
Durch die Implementierung der Präsentations-Logik im ViewModel koordiniert diese die Interaktion zwischen den Model‘s und der View.
Das ViewModel besteht aus:
Durch-gereichte / Gekapselte Model‘s
Bindbare Eigenschaften für die View
Bindbare Kommandos für die View
Benachrichtigungen für die View
Gekapselte Präsentations-Logik
Ein ViewModel implementiert Model’s und wird für die Aufgabenstellung einer View entwickelt.
Während das Model System-unabhängig ist, tendiert das ViewModel zu einem konkreten System wie WPF, Silverlight, Windows Store App, etc.
Das ViewModel ist eine nicht-visuelle Klasse das weder von einer visuellen Klasse abgeleitet wird noch visuelle Objekte implementiert.
Das ViewModel besitzt keine Kenntnisse oder Referenz über die View, d.h. eine Abhängigkeit von der View darf nicht entstehen. Soweit nicht gekapselt könnte das ViewModel jedoch über das Model Kenntnisse über den DataService haben.
Das ViewModel arbeitet mit bereits initiierten Model’s oder stößt das Befüllen der Model’s mittels der DataAccess-Schicht an.
Wenn Ihre Anwendungs-Domäne aus mehreren ViewModel’s besteht empfiehlt es sich die benötigten Interfaces in einer abstrakten Klasse ViewModelBase zu implementieren und von diesen abzuleiten.
Test : Das ViewModel ist unabhängig von der View und dem Model testbar.
Die Daten die in der View präsentiert werden, können im ViewModel manipulieren und aufbereitet werden. Separate Konverter-Klassen (IValueConverter
) werden unabhängig dem Binding-Objekt in der View zugewiesen und übernehmen die Aufgabe der Konvertierung in Richtung View-ViewModel und umgekehrt.
Das ViewModel implementiert Befehle die als Eigenschaft vom Typ ICommand
bereitgestellt werden. Diese wiederum können später in der View gebunden werden:
<Button Content="{Binding Email}"
Command="{Binding SendenCommand}" />
Bindung : Das ViewModel kann die Eigenschaften des Model‘s direkt der View zugänglich machen. Alternativ kapselt das ViewModel die Eigenschaften des Models, bereitet die Daten auf und stellte diese der View dann zur Verfügung. Entscheidend ist die nicht redundante Änderungsbenachrichtigung der View die entweder vom Model oder vom ViewModel kommen. Hierzu implementieren Sie im ViewModel bzw. Model INotifyPropertyChanged
, INotifyCollectionChanged
oder ObservableCollection<T>
.
Das ViewModel definiert logische Zustände und informiert über INotifyPropertyChanged
und INotifyCollectionChanged
die View über Änderungen die dem Benutzer visuell dargestellt werden können.
Validierung : Für die Datenüberprüfung und Fehlerberichterstattung wird INotifyDataErrorInfo
im ViewModel implementiert oder diese Aufgabe übernimmt auch das Model.
View
Die Datenbindungs-Infrastruktur ermöglicht eine lose Kopplung, bei der die View und die verknüpften Daten synchronisiert bleiben bzw. alle Benutzereingaben zu den entsprechenden Befehlen geleitet werden.
Die View besteht aus:
UI-Elemente (XAML, DataTemplate’s, UserControl’s, Style‘s, Resource’s, etc.
Property-Bindungen auf Eigenschaften der ViewModel
Command-Bindungen auf Eigenschaften der ViewModel
UX (User Experience)-Logik
Die View geht eine 1:1 Beziehung mit dem entsprechenden ViewModel ein. Eine View kann sich aus mehreren Views (z.B. UserControl’s) zusammensetzen, die wiederum ihr eigenes ViewModel besitzen.
Die UI-Elemente binden ihre Eigenschaften mit einem Binding-Objekt an das dazugehörige ViewModel:
<... Text="{Binding Email}"
Command="{Binding SpeichernCommand}" ... />
UX : In der dazugehörigen Code-Behind-Klasse liegt kein bis wenig Code der sich gekapselt nur auf die UX (User Experience)-Logik auswirkt.
Separate Konverter-Klassen die IValueConverter
implementieren werden unabhängig dem Binding-Objekt in der View zugewiesen und übernehmen die Aufgabe der Konvertierung in Richtung View-ViewModel und umgekehrt.
Bindung : Für umgehende Aktualisierung der UI-Elemente ist es wichtig dass die gebunden Quelleigenschaft des Model’s bzw. des ViewModel‘s die View korrekt benachrichtigt. Dies tun sie, wenn Sie die folgenden Interfaces implementiert haben: INotifyPropertyChanged
, INotifyCollectionChanged
, ObservableCollection<T>
, oder INotifyDataErrorInfo
.
Die konkrete Umsetzung der Bindung können Sie im Kapitel Datenbindung nachvollziehen.
Super-Übersicht um pregnant die wichtigsten Begriffe für MVVM miteinander zu verknüpfen.
Schön zu hören, das motiviert.
Pingback: Attila Krick | Externe hilfreiche Quellen aus der IT-Welt und darüber hinaus