[MVVM] INotifyPropertyChanged ViewModel vs Model
-
Es gibt im Internet und in Büchern eine ziemlich geteilte Meinung was die Implementierung der INotifyPropertyChanged-Schnittstelle und MVVM angeht, manche machen es im ViewModel, manche im Model... ich bin inzwischen recht geteilter Meinung und überlege es in beiden zu tun (zumal mein Verständlich vom ViewModel nicht zwangsweise einer 1:1 Abbildung einer Model-Klasse ist, sondern je nach Fall auch mal mehrere zusammenfasst und einen Teil der Daten veröffentlicht) und wollte dazu ein paar Meinungen hören.
Ich habe folgende Situation: Für die Neuentwicklung einer Anwendung soll zumindest vorgesehen sein, das man relativ unabhängig von der UI möglichst viel Logik gemeinsam als Service vorhält hält. Dabei wird unter anderem ein Datenmodel (Entity Framework 4.2; Code First) verwendet, das im wesentlichen mein Model ist. Sowohl ASP.Net als auch WPF, Silverlight und wohl WinRT verwenden wohl u.a. die INotifyPropertyChanged-Schnittstelle, so das ich derzeit meine erste Überlegung überdenke diese ausschließlich im ViewModel zu halten.
Mein Model enthält nur grundlegende Logik wie z.B. berechnete Spalten, die sich effektiv ändern, wenn sich ein oder mehrere andere Werte ändern. Ohne die Implementierung der INotifyPropertyChanged-Schnittstelle müsste ich nun für jede UI einen Wrapper schreiben der diese Logik umsetzt, den das ViewModel gehört meines Erachtens nicht nach ASP.Net.
Daher bin ich aktuell am überlegen sowohl dem Model wie auch dem ViewModel diese Schnittstelle (oder eine davon abgeleitete) zu verpassen, und im ViewModel die Events des Models abzufangen und bei Bedarf (je nach offen gelegten Feldern) weiter zu leiten.
Meinungen?
-
Hallo asc,
eigentlich bin ich selber auch dafür, nur im ViewModel die INotifyPropertChanged-Schnittstelle zu implementieren (da sie hauptsächlich ja nur von WPF bzw. Silverlight benötigt wird), jedoch gibt es wohl auch Gründe dafür, dies ebenso im Model zu machen (sofern das Model noch in anderen Szenarien benutzt wird).
Durch die Schichten-Trennung hat man ja immer gewisse Doppelimplementationen (d.h. Daten durchreichen etc.) - es sollte m.E. jedoch immer die Möglichkeit geben direkt Daten zu modifizieren, ohne daß jede Änderung eine Aktualisierung der UI zur Folge hat (über den DAL wird man sicherlich z.B. Massenimporte nutzen, anstatt über den BL (Model)).Für die Erzeugung der INotifyPropertyChanged-Schnittstelle kann ich dir Yappi (Yet Another Property Proxy Implementation) empfehlen, damit man nicht mehr händisch überall den (fehleranfälligen) PropertyChanged-Aufruf durchführen muß.
-
Th69 schrieb:
Für die Erzeugung der INotifyPropertyChanged-Schnittstelle kann ich dir Yappi (Yet Another Property Proxy Implementation) empfehlen, damit man nicht mehr händisch überall den (fehleranfälligen) PropertyChanged-Aufruf durchführen muß.
Da scheint mir persönlich "NotifyPropertyWeaver" die bessere Wahl zu sein...
-
Es spricht überhaupt nichts dagegen auch in den Models das INotifyPropertyChanged zu implementieren.
Es ist am Ende ein einfaches Interface welches ein C# Evenet implementiert haben möchte.
Das ist in den Model Daten völlig normal und wird immer gemacht, warum sollte das INotifyPropertyChanged da eine Ausnahme sein.Implementiere es dort wo es gebraucht wird und Fertig.
Bei MVVM will man ja die ViewModels unabhängig von einer View haben, ob die Models nun ein Interface implementieren oder nicht ist dabei völlig Irrelevant. Testbar ist alles weiterhin völlig isoliert.
-
@asc
Kind Of Magic ist auch schön (http://kindofmagic.codeplex.com/)
da braucht man nur ein Attribut an die Klasse wo alle Properties das Notify bekommen sollen.//Dazu
"fehleranfällig" ist das PropertyChanged nicht unbedingt
Ich mach es auch händisch:public char Value { get { return _value; } set { _value = value; NotifyPropertyChanged(() => Value); } } private char _value;
wenn man "() => Value" falsch schreibt baut es nicht, und man kann es sehr gut Refactoren lassen.
-
David W schrieb:
@asc
Kind Of Magic ist auch schön (http://kindofmagic.codeplex.com/)
da braucht man nur ein Attribut an die Klasse wo alle Properties das Notify bekommen sollen.Mir gefällt an der Beschreibung von NotifyPropertyWeaver (Habe den aber selbst erst heute gefunden), das dieser auch zusammengesetzte Felder (z.B. Berechnetes Feld aus 2 Properties) von sich aus berücksichtigt, und man nur das Interface hinschreiben muss.
David W schrieb:
//Dazu
"fehleranfällig" ist das PropertyChanged nicht unbedingt
Ich mach es auch händisch:Das Problem bei der Variante über Lamda-Expressions und Reflection ist laut meiner Recherche (noch nicht verifiziert) das diese wesentlich langsamer zur Laufzeit sind.
-
Die Lambda Expressions sind in der Tat vergleichsweise langsam. Nicht nur die Reflection ist problematisch; es wird auch jedesmal ein Closure-Objekt erzeugt mit verstecktem
this
. Das ist der Preis, den man für die Compile-Time Fehlermeldungen bezahlen muss.$EDIT: Sagt der Dozent, der bei Microsoft arbeitet bzw. von denen gestellt wird
-
Das es lamgsamer ist kann man auch durch normale Recherche raus finden.
Für gewöhnlich macht man das auch nur für Properties die Gebunden werden sollen, dadurch spielt es am Ende keine rolle da der UI Renderprozess sowieso recht langsam ist ^^ da merkt man es gar nicht.
-
David W schrieb:
Für gewöhnlich macht man das auch nur für Properties die Gebunden werden sollen, dadurch spielt es am Ende keine rolle da der UI Renderprozess sowieso recht langsam ist ^^ da merkt man es gar nicht.
Da man das Model mit Sicherheit nicht nur in der UI verwendet, würde ich das so nicht pauschalisieren. Ich bin zwar gegen vorträgliche Optimierung, aber gleichzeitig auch kein Freund davon bekannte Bremsen einzubauen, wenn sich der Mehrwert in Grenzen hält (Zumal es in diesem Fall ja mehrere Alternativen gibt).
Mein eigentliches Anliegen ist aber imho inzwischen geklärt.
-
asc schrieb:
David W schrieb:
@asc
Kind Of Magic ist auch schön (http://kindofmagic.codeplex.com/)
da braucht man nur ein Attribut an die Klasse wo alle Properties das Notify bekommen sollen.Mir gefällt an der Beschreibung von NotifyPropertyWeaver (Habe den aber selbst erst heute gefunden), das dieser auch zusammengesetzte Felder (z.B. Berechnetes Feld aus 2 Properties) von sich aus berücksichtigt, und man nur das Interface hinschreiben muss.
David W schrieb:
//Dazu
"fehleranfällig" ist das PropertyChanged nicht unbedingt
Ich mach es auch händisch:Das Problem bei der Variante über Lamda-Expressions und Reflection ist laut meiner Recherche (noch nicht verifiziert) das diese wesentlich langsamer zur Laufzeit sind.
Die Idee hatte ich auch mal.
Messungen haben einen Performanceunterschied von mehreren Größenordnungen zwischen der "string" und der "Lambda-Ausdruck" Variante ergeben. Ist imho eher nicht zu empfehlen. Das Teure ist afair das Anlegen der Expression und nicht so sehr der Zugriff auf den Expressiontree.
-
Ändert aber nichts am Ergebnis.