2011-02-04 16 views
5

Pracuję nad dużą aplikacją Silverlight, która używa dupleksu Net.TCP do rozmowy z zapleczem WCF. Jestem w trakcie przenoszenia tej aplikacji z podejścia MVC do MVVM. Jednak walczę z właściwym sposobem na wdrożenie moich ViewModels. Korzystamy z generowanych przez WCF serwerów proxy dla naszego modelu, który jest dość złożony, obejmuje dziesiątki klas, wiele zbiorów i wiele relacji wiele do wielu. Na przykład użytkownik może należeć do wielu pokoi, pokój może mieć wielu użytkowników, użytkownik może mieć wiele plików współdzielonych, a każdy plik współdzielony może być współdzielony z dowolnym pomieszczeniem, którego użytkownik jest aktualnie częścią. Coś w tym rodzaju.Najlepsza praktyka synchronizacji modeli i ViewModels

Ponadto, ponieważ używamy WCF w trybie duplex, zmiany w modelu mogą być wyzwalane przez użytkownika końcowego lub przez usługę WCF na zapleczu. Innymi słowy, model, którego używamy, jest o kilka rzędów wielkości bardziej skomplikowany niż typowy "model", który można zobaczyć w różnych książkach/artykułach/postach na blogu MVVM. I tu pojawia się problem, ponieważ utrzymanie synchronizacji warstwy ViewModel z warstwą modelu staje się kłopotliwe.

Oto typowy problem. Nowy "Użytkownik" dołącza do "pokoju", więc usługi WCF wysyłają powiadomienie "SessionAdded" do wszystkich pozostałych użytkowników w pokoju. Powiadomienie SessionAdded przenosi obiekt Session, który ma połączony Room i połączony obiekt User. Obiekt ten, który otrzymuje deserializację z usługi WCF, jest w zasadzie taki sam, jak obiekt Room na lokalnym kliencie i prawdopodobnie zawiera większość tych samych danych, ale z pewnością nie ma tych samych danych w przypadku jednego obiektu, a przynajmniej niektóre z nich. danych (na przykład jego pusta kolekcja Whiteboard) jest z pewnością błędna. Musimy więc w jakiś sposób wziąć te nadchodzące dane i połączyć je z naszym istniejącym modelem. A następnie musimy utworzyć ViewModels na górze każdego z nowych obiektów i/lub zaktualizować istniejące modele ViewModels o nowe obiekty i/lub ich dane.

W tej chwili zajmujemy się tym poprzez różne modele ViewModels reagować na odpowiednie zdarzenia powiadomienia WCF, i zrobić wszystko, aby naprawić swoje podstawowe modele i pokrewne modele widoku. Wymyśliliśmy kilka sztuczek, takich jak SynchronizedObservableCollection (niejasno podobny do tego here), który obserwuje (na przykład) Room.Sessions ObservableCollection i automatycznie tworzy odpowiednie modele SessionViewModels i umieszcza je w kolekcji RoomViewModel.SessionViewModels. Używamy również narzędzia ViewModelFactory, które buforuje modele widoku i zapewnia, że ​​moduł SessionViewModel, który otacza daną sesję, pozostaje taki sam, nawet jeśli podstawowy obiekt sesji zostanie zmieniony. (Jeśli to ma znaczenie, używamy podejścia opartego na viewmodel, ponieważ duża część tego, czego potrzebujemy, to tworzenie nowych elementów interfejsu użytkownika w odpowiedzi na zmiany w ViewModelu wywołane przez nasze powiadomienia WCF.)

wszystko to działa. Gruntownie. Większość czasu. Wiesz. Ale jest dużo kodu do utrzymania i łatwo się pomylić. Testy jednostkowe są przydatne, o ile pamiętasz, co powinno się wydarzyć, ale zanim skończysz przetwarzanie swojego 20. kaskadowego zdarzenia CollectionChanged, ciężko jest śledzić, jak to wszystko pasuje do siebie i na co próbujesz. . Innymi słowy, wszystko jest cholernie kruche.

Wydaje mi się, że jest to rodzaj scenariusza, na który musiało się natknąć wiele osób. Ciekawi mnie, jak inni się z tym zmierzyli. Mogę wymyślić kilka podejść, aby być może lepiej:

(1) Traktuj model po stronie klienta jako rodzaj bazy danych, która musi być całkowicie spójna, i zaimplementuj warstwę dostępu do danych po stronie klienta, której zadaniem jest ma to na celu utrzymanie spójności modelu. Wszystkie aktualizacje modelu, zarówno od użytkownika, jak i serwera, będą musiały przejść przez tę warstwę. Byłoby trochę podobne do Entity Framework, w tym myRoom.Users.Add(myUser) automatycznie ustawiłoby myUser.Room = myRoom i na odwrót, i tak dalej. (To jest szczególnie ta część, która wydaje się, że ktoś powinien już się rozwinąć, chociaż jeszcze jej nie znalazłem.)

(2) Przechowywać na czymś takim jak Truss lub Obtics, aby zachować synchronizację wszystkich elementów. Nie jestem do końca pewien, jak to jeszcze zadziała, ale brzmi to w teorii, jak powinno być możliwe.

I ... co jeszcze? Jestem ciekawy co do wzorców lub ram, które zostały użyte do rozwiązania tego problemu.

Odpowiedz

3

Rozumiem twój ból - obecnie tworzę aplikację do kompleksowej wizualizacji danych, wykorzystując wzór MVVM. Jednym z naprawdę ważnych pytań, które należy sobie postawić, jest: "Czy model widoku dodaje wartość wszędzie tam, gdzie go wykorzystujesz?", Mówiąc słowami, czy istnieją miejsca, w których po prostu przekazuje on swoje właściwości na warstwę modelu do widoku?

Często stwierdzam, że istnieją obszary kodu, zazwyczaj na poziomie szczegółowości (np. Właściwości obiektu osoby, wieku, nazwy, imienia), gdzie model widoku faktycznie nie dodaje żadnej wartości, podczas gdy wyższy poziom kursu, dodaje wartości poprzez strukturę widoków/okien itp ...

Mam tendencję do adaptacyjnego podejścia do MVVM, na najwyższym poziomie (Windows, szyby, formularze) Zawsze mam model widoku, ale jeśli części modelu widoku są tak proste, że model widoku nie dodaje żadnej wartości, wystawiam je bezpośrednio na widok. Ponadto, w niektórych przypadkach musisz wystawić model bezpośrednio na widok, aby uzyskać lepszą wydajność.

Wreszcie, jeśli okaże się, że trzeba ponownie wprowadzić model widok rozwiązać skomplikowane wiązania problemu, pisałem o prosty wzór, mini-MVVM, który ma zastosowanie lokalnego modelu wyświetlania:

http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/

Nadzieję, że pomaga.

+0

Zasadniczo to, co robię: nie jestem purystą :-). Każdy mój model ViewModels ma właściwość Model, która udostępnia model bazowy. Ponieważ Model w tym przypadku jest zawsze klasą generowaną przez WCF, implementuje INotifyPropertyChanged, więc działa dość dobrze jako źródło wiązania. Jedyne właściwości, które dodaję do mojego ViewModel, to te, które faktycznie dodają wartość w pewien sposób. Ale wciąż mam do czynienia z problemem Modelu wymagającego odświeżenia, kiedy serwer wysyła wiadomość do klienta z zaktualizowanym Modelem. –

Powiązane problemy