2012-12-12 10 views
7

Beispiele für WPF MVVM-Apps, die ich im Internet gesehen habe, betrachten VM als eine Schicht, die mit einer Serviceebene interagiert, die entweder "alte" Ereignisse aus einer externen Bibliothek verwendet oder mit ihr interagiert Web mit HTTP oder was auch immer. Aber was, wenn ich alle M, V, VM, Service und andere Teile selbst baue? Wie baut man die Interaktion zwischen der Service-Schicht und der View-Model-Ebene richtig auf? Kann ich einfach ObservableCollection<OrderModel> in den Service einfügen und es aus dem ViewModel für die Ansicht zurückgeben, oder wird es als ein schlechter Ansatz betrachtet und gibt es bessere Alternativen?ObservableCollection in der Serviceebene der WPF MVVM-Anwendung

Antwort

6

Sie können dies tun - natürlich können Sie. Der Hauptgrund für eine solche Maßnahme wäre die Reduzierung von Mehrfachkopien in mehreren WPF-Anwendungen.

Eine Herausforderung, die Sie in einigen Szenarios haben können, sind je nach Ihrer Dienstschicht-/Datenschichtimplementierung lang andauernde Dienste, die wiederum Datenbankverbindungen verwenden. ObservableCollections sind verlockend, da die Service-Schicht Änderungen, die von einer Anwendung an einen Datenspeicher vorgenommen werden, automatisch synchronisiert. Es wird jedoch kompliziert, wenn Sie Änderungen mitteilen möchten, die von den Daten selbst stammen (d. h. als Reaktion auf einen anderen Prozess, der Daten erstellt/ändert). Die Serviceebene kann die Instanz nicht wirklich ersetzen (z. B. bei großen Änderungen), da sie nicht mehr der alleinige Besitzer der Referenz ist - aber selbst wenn, könnte sie die Instanz ersetzen Brechen Sie jede Bindung, die die UI an die Sammlung hat.

Sie bleiben also dabei, die eine Instanz auf dem neuesten Stand zu halten. Wenn Ihre Dienste an eine Datenbank gebunden sind, besteht die einzige einfache Möglichkeit, eine ObservableCollection auf dem neuesten Stand zu halten, nach dem Ausrichten der Datenbank, wenn Sie nicht einen langwierigen Überwachungsprozess in Ihrem Dienst kodieren. Kontexte (im Fall von Linq zu Sql oder EF) öffnen - weil ansonsten verwandte Objekte usw. nicht abrufbar sein werden (es sei denn, man zwingt alle Objekte, auf einmal gelesen zu werden - was nicht skalierbar ist).

Okay, so ist es möglich, eine Form der Management-Schicht zu schreiben, die die Verbindungen für Sie verwalten kann - aber zusätzlich zu den unvermeidlichen Abfragen, oder vielleicht SQL Server-Benachrichtigungen, die Sie verwenden könnten, glaube ich, dass der Code ziemlich kompliziert werden könnte .

Das heißt, es hängt wirklich davon ab - auf dieses spezielle Problem muss man achten, aber es könnte sein, dass Sie eine Architektur und Umgebung haben, in der solche Dinge einfach keine Rolle spielen.

Mein Rat, wenn Sie es versuchen wollen - gehen Sie voran. Für mich? Ich habe darüber nachgedacht - und über das Hinzufügen von INotifyPropertyChanged zu einigen Domänenmodellen hinaus bleibe ich bei der Idee, dass eine Anwendung ihre eigene VM hat. Mehrere Anwendungen können sich dieselbe VM teilen. Dies ist jedoch nicht der interne Service Layer selbst.

Eine Service-Schicht bietet Zugriff auf Daten und Geschäftslogik in einer typischen One-Shot-Art. Klassen im VM-Muster sollen eine viel längere Lebensdauer haben - und der Versuch, eine lang laufende Service-Schicht zu programmieren, ist notorisch sehr schwierig - besonders, wenn Sie versuchen wollen, alle Probleme zu lösen, die alle zukünftigen Anwendungen darstellen könnten. Unvermeidlich werden Sie damit enden, Dienste oder VM-Typen innerhalb der Service-Schicht nur für eine einzelne Anwendung zu codieren - in diesem Fall wäre es genauso gut in die Codebasis dieser App gegangen.

0

Ich würde das aus einer Reihe von Gründen nicht tun. Sie sind hier dokumentiert: Common mistakes with an observable collection

Der Autor durchläuft mehrere Fehler, die Menschen mit ihnen machen, einschließlich der Verwendung in der Service-Schicht.

+0

Der Artikel sagt im Abschnitt "Verwenden im Modell", dass die Verwendung von OC in Modellen schlecht ist, aber ich habe viele Beispiele gesehen, wenn Modelle in der Ansicht ohne Konvertierung gegeben werden. Eine der Empfehlungen war: "Wenn ein Modell INotifyPropertyChanged implementiert, verwenden Sie es; andernfalls konvertieren Sie es". Die Verwendung von beobachtbaren Sammlungen in Modellen wird daher von niemandem als schlechte Praxis angesehen ... Wie auch immer, die Frage ist: Was ist der alternative Weg, richtiger Weg? – Athari

+0

Ich glaube, der alternative Weg (richtiger Weg) ist IEnumerable zu verwenden. Wie bei @PeteH vorgeschlagen, versuche OC nur so weit wie möglich zu verwenden, auch bekannt als ViewModel. Und schreibe eine CollectionViewModel-Klasse, die die ObservableCollection von ViewModels als eine Eigenschaft mit Abonnements für OnCollectionChanged usw. verfügbar macht. – Heliac

2

Ich wäre versucht, eine ObservableCollection nur an dem Punkt zu verwenden, an dem der "beobachtbare" Aspekt relevant ist, was im Allgemeinen die VM ist, die etwas dem V aussetzt. Weiter unten im Stapel (dh dem M) würde ich Versuchen Sie, bei allgemeineren Dingen wie Listen und Sammlungen zu bleiben (es sei denn, Sie brauchen etwas anderes). Es ist einfach genug für die VM, auf jeden Fall eine ObservableCollection basierend auf einem alten IEnumerable zu erstellen.

Eine vernünftige Frage aber, vor allem als ObservableCollection die Platzierung im System.Collections-Namespace scheint zu zeigen, dass Microsoft vor allem nicht denken, dies als eine spezialisierte Klasse (und schon gar nicht wpf spezifisch).

+0

Das Problem mit "traditionellen" Listen und Enumerables ist, dass ich die Ansicht über das Viewmodel immer noch aktualisieren muss, wenn etwas ist zur Liste hinzugefügt; Das viewmodel muss daher vom Dienst über ein neues Element benachrichtigt werden. Wenn ich Ereignisse hinzufüge, sieht es wie eine schlechte (und wahrscheinlich fehlerhafte) Implementierung der beobachtbaren Sammlung aus ... – Athari

+0

@Athari Ich kann sehen, woher du kommst - es macht sicherlich keinen Sinn, deine eigene ObservableCollection zu implementieren. Schauen Sie weiter unten, wie wird der Service wissen, dass sich die Dinge geändert haben? – PeteH

+0

@Athari - Genau das mache ich. Wenn ich ein neues Element programmgesteuert hinzufüge (dh die neue DataGrid-Zeile nicht, aber eine Entität hinzufügend), habe ich ein OnEntityAdded-Ereignis, das ich aus der Create-Methode in meinem Repository austausche: ** OnEntityAdded (new ModelEntityAddedEventArgs (entity)) ** . Wie Sie sehen können, wird die Entität in den Ereignisargumenten übergeben. Meine Serviceebene abonniert dieses Ereignis. – Heliac