Podstawowe pojęcia MVVM - co powinien robić ViewModel?

84

Próbując zrozumieć koncepcje MVVM, przeczytałem już kilka blogów i przyjrzałem się kilku projektom.

Z tego, co rozumiem, Widok jest głupi, po prostu wie, jak przedstawić coś, co jest mu przekazywane.

Modele to po prostu zwykłe dane, a ViewModel to coś, co działa jak wypełnienie pomiędzy nimi, że powinien pobierać informacje z Modelu i przekazywać je do Widoku , a Widok powinien wiedzieć, jak je przedstawić. Lub odwrotnie, jeśli informacje w Widoku ulegną zmianie, zmiana powinna zostać przekazana do Modelu .

Ale nadal nie mam pojęcia, jak zastosować tę koncepcję. Czy ktoś może wyjaśnić bardzo prosty scenariusz, abym mógł zrozumieć koncepcję? Obejrzałem już kilka projektów, ale nadal nie ma to pełnego sensu, więc jeśli ktoś mógłby napisać to prostym angielskim, byłoby miło.

RKM
źródło
2
Nie mogę zgodzić się ze stwierdzeniem, że „po prostu umiem przedstawić coś, co jest mu przekazane”. Widok pobiera dane z maszyny wirtualnej. Nikt nie przekazuje do niego danych. Nikt nie wie o widoku. To ważna różnica w porównaniu z MVP. W MVP (możesz o tym myśleć jak o prostej aplikacji WPF z logiką codebehind, jest to wzorzec MVP) codebehind jest prezenterem, który przekazuje dane do View, jak powiedziałeś.
Grigorij

Odpowiedzi:

149

Lubię o tym myśleć w ten sposób:

Widoki, jak mówisz, są głupie. Josh Smith, autor przełomowego i często powiązanego artykułu MSDN na temat MVVM, powiedział, że poglądy to „ubrania, które noszą dane”. Widoki w rzeczywistości nigdy nie zawierają danych ani bezpośrednio nimi manipulują, są po prostu powiązane z właściwościami i poleceniami modeli widoków.

Modele to obiekty modelujące domenę aplikacji , tak jak w przypadku obiektów biznesowych. Czy Twoja aplikacja to sklep muzyczny? Być może obiektami modelowymi będą artyści, albumy i piosenki. Czy Twoja aplikacja jest przeglądarką schematów organizacyjnych? Być może obiektami modelu będą menedżerowie i pracownicy. Te obiekty modelu nie są powiązane z żadnym rodzajem renderowania wizualnego i nie są nawet bezpośrednio związane z aplikacją, w której je umieszczasz - obiekty modelu powinny mieć sens same w sobie jako rodzina obiektów, które reprezentują jakiś rodzaj domeny. Warstwa modelu zazwyczaj zawiera również takie elementy, jak akcesory usług.

To prowadzi nas do Viewmodels. Czym oni są? Są to obiekty modelujące aplikację GUI, co oznacza, że ​​zapewniają dane i funkcje do wykorzystania przez widoki. To one definiują strukturę i zachowanie faktycznie budowanej aplikacji. W przypadku obiektów modelu domeną jest dowolna wybrana domena (sklep muzyczny, przeglądarka schematów organizacyjnych itp.), Ale w przypadku modelu widoku domena jest aplikacją graficzną. Twoje modele widoku będą hermetyzować zachowanie i dane wszystkiego, co robi Twoja aplikacja. Będą ujawniać obiekty i listy jako właściwości, a także takie rzeczy, jak Polecenia. Polecenie to po prostu zachowanie (w najprostszym przypadku wywołanie metody) zawinięte w obiekt, który je przenosi - ta idea jest ważna, ponieważ widoki są sterowane przez wiązanie danych, które dołącza kontrolki wizualne do obiektów. W MVVM nie dajesz przyciskowi metody obsługi kliknięcia,

Dla mnie najbardziej zagmatwane były następujące elementy:

  • Mimo że modele widoków są modelami aplikacji graficznej, nie odwołują się bezpośrednio ani nie używają pojęć wizualnych. Na przykład nie chcesz, aby odwołania do formantów systemu Windows w modelach widoku były wyświetlane w widoku. ViewModels po prostu ujawniają dane i zachowania kontrolkom lub innym obiektom, które zostaną z nimi powiązane. Na przykład - czy masz widok zawierający ListBox? Twój Viewmodel prawie na pewno będzie zawierał jakąś kolekcję. Czy Twój widok ma przyciski? Twój Viewmodel prawie na pewno będzie zawierał jakieś polecenia.
  • Istnieje kilka rodzajów obiektów, które można uznać za „modele widoków”. Najłatwiejszy do zrozumienia rodzaj modelu widoku to taki, który bezpośrednio reprezentuje kontrolkę lub ekran w relacji 1: 1, tak jak w przypadku „screen XYZ ma pole tekstowe, pole listy i trzy przyciski, więc model widoku wymaga ciągu, kolekcji, i trzy polecenia. " Innym rodzajem obiektu, który mieści się w warstwie modelu widoku, jest otoka wokół obiektu modelu, która nadaje mu zachowanie i sprawia, że ​​jest on bardziej użyteczny w widoku - w tym miejscu można zapoznać się z koncepcjami „grubych” i „cienkich” warstw modelu widoku. „Cienka” warstwa modelu widoku to zestaw modeli widoków, które eksponują obiekty modelu bezpośrednio na widoki, co oznacza, że ​​widoki wiążą się bezpośrednio z właściwościami obiektów modelu. Może to działać w przypadku prostych widoków tylko do odczytu, ale co, jeśli chcesz, aby zachowanie było powiązane z każdym obiektem? Nie chcesz tego w modelu, ponieważ model nie jest powiązany z aplikacją, jest powiązany tylko z Twoją domeną. Możesz umieścić go w obiekcie, który otacza obiekt modelu i oferuje bardziej przyjazne dla powiązań dane i zachowania. Ten obiekt otoki jest również uważany za model widoku, a posiadanie ich skutkuje „grubszą” warstwą modelu widoku, w której widoki nigdy nie są bezpośrednio powiązane z niczym w klasie modelu. Kolekcje będą zawierać modele widoków, które zawijają modele, a nie tylko same modele. Możesz umieścić go w obiekcie, który otacza obiekt modelu i oferuje bardziej przyjazne dla powiązań dane i zachowania. Ten obiekt otoki jest również uważany za model widoku, a posiadanie ich skutkuje „grubszą” warstwą modelu widoku, w której widoki nigdy nie są bezpośrednio powiązane z niczym w klasie modelu. Kolekcje będą zawierać modele widoków, które zawijają modele, a nie tylko same modele. Możesz umieścić go w obiekcie, który otacza obiekt modelu i oferuje bardziej przyjazne dla powiązań dane i zachowania. Ten obiekt otoki jest również uważany za model widoku, a posiadanie ich skutkuje „grubszą” warstwą modelu widoku, w której widoki nigdy nie kończą się bezpośrednio powiązaniem z niczym w klasie modelu. Kolekcje będą zawierać modele widoków, które zawijają modele, a nie tylko same modele.

Królicza dziura sięga głębiej - istnieje wiele idiomów, które należy wymyślić, takich jak ValueConverters, które sprawiają, że MVVM działa, i jest wiele do zastosowania, gdy zaczynasz myśleć o takich rzeczach, jak Blendability, testowanie i jak przekazywać dane w aplikacji i upewnić się, że każdy model widoku ma dostęp do potrzebnego zachowania (w tym miejscu pojawia się zastrzyk zależności), ale mam nadzieję, że powyższe jest dobrym początkiem. Kluczem jest myślenie o wizualizacjach, domenie oraz strukturze i zachowaniu rzeczywistej aplikacji jako o trzech różnych rzeczach.

nlawalker
źródło
3
+1 - Skończyłem tutaj, ponieważ byłem zdezorientowany przez „wrapper” ViewModel napotkany w przykładowym kodzie. Dziękuję za wyjaśnienie mi tego :-)
Riegardt Steyn
1
Świetna odpowiedź - szkoda, że ​​nie mogę +10.
Nick Hodges
1
@nlawalker Bardzo niesamowite! Powyższy podwójny komentarz u mnie od dawna wprawia mnie w zakłopotanie. Wiele artykułów i blogów mówi tylko o „kluczowych funkcjach” MVVM, ale kiedy spróbujesz się z tym uporać, sprawy zaczynają być bardzo skomplikowane ! Na przykład „Jak poruszać się po tych widokach?” „Jaka jest odpowiednia szczegółowość podczas projektowania modeli widoków?” „Czy widok musi mieć dopasowany ViewModel, czy też jeden ViewModel może być ponownie użyty w różnych widokach?” Twoje wyjaśnienie dotyczące ViewModel utworzonego za pomocą „Slim VM” i „Thick VM” naprawdę ma sens! Próbuję go, działa dobrze, więc daleko! :)
Pazur
@nlawalker Thanks! I jeszcze jedno pytanie: mam treeView i tworzę TreeViewViewModel. Tak więc, jeśli utworzę metody takie jak: ExpandTree () w moim ViewModel. Czy to właściwy sposób?
user2545071
Wow, to świetny artykuł, całkiem dobra robota @nlawalker
Vivek Shukla
26

Korzystanie z tej niezwykle pomocny artykuł jako źródła, tutaj jest podsumowanie dla View , ViewModel i model .


Widok:

  • Widok jest elementem wizualnym, takim jak okno, strona, kontrolka użytkownika lub szablon danych. Widok definiuje kontrolki zawarte w widoku oraz ich układ wizualny i styl.

  • Widok odwołuje się do modelu widoku poprzez swoją DataContextwłaściwość. Kontrolki w widoku są danymi powiązanymi z właściwościami i poleceniami uwidocznionymi przez model widoku.

  • Widok może dostosować zachowanie powiązania danych między widokiem a modelem widoku. Na przykład widok może wykorzystywać konwertery wartości do formatowania danych, które mają być wyświetlane w interfejsie użytkownika, lub może używać reguł walidacji, aby zapewnić użytkownikowi dodatkowe sprawdzanie poprawności danych wejściowych.

  • Widok definiuje i obsługuje wizualne zachowanie interfejsu użytkownika, takie jak animacje lub przejścia, które mogą być wyzwalane w wyniku zmiany stanu w modelu widoku lub w wyniku interakcji użytkownika z interfejsem użytkownika.

  • Widok związany z kodem może definiować logikę interfejsu użytkownika w celu zaimplementowania zachowania wizualnego, które jest trudne do wyrażenia w języku XAML lub które wymaga bezpośrednich odwołań do określonych kontrolek interfejsu użytkownika zdefiniowanych w widoku.

UWAGA:
Ponieważ model widoku nie powinien mieć wyraźnej wiedzy na temat określonych elementów wizualnych w widoku, kod służący do programowego manipulowania elementami wizualnymi w widoku powinien znajdować się w kodzie widoku lub być hermetyzowany w zachowaniu.


Zobacz model:

  • Model widoku jest klasą niewizualną i nie pochodzi od żadnej klasy bazowej WPF ani Silverlight. Hermetyzuje logikę prezentacji wymaganą do obsługi przypadku użycia lub zadania użytkownika w aplikacji. Model widoku można testować niezależnie od widoku i modelu.

  • Model widoku zazwyczaj nie odnosi się bezpośrednio do widoku. Implementuje właściwości i polecenia, z którymi widok może wiązać dane. Powiadamia widok o wszelkich zmianach stanu za pośrednictwem zdarzeń powiadamiania o zmianach za pośrednictwem interfejsów INotifyPropertyChangedi INotifyCollectionChanged.

  • Model widoku koordynuje interakcję widoku z modelem. Może konwertować dane lub manipulować nimi, aby były łatwo używane przez widok i może implementować dodatkowe właściwości, które mogą nie występować w modelu. Może również implementować walidację danych za pośrednictwem interfejsów IDataErrorInfolub INotifyDataErrorInfo.

  • Model widoku może definiować stany logiczne, które widok może przedstawiać użytkownikowi wizualnie.

UWAGA:
Wszystko, co jest ważne dla logicznego zachowania aplikacji, powinno znaleźć się w modelu widoku. Kod do pobierania lub manipulowania elementami danych, które mają być wyświetlane w widoku za pośrednictwem powiązania danych, powinien znajdować się w modelu widoku.


Model:

  • Klasy modelu to niewizualne klasy, które hermetyzują dane aplikacji i logikę biznesową. Odpowiadają za zarządzanie danymi aplikacji oraz zapewnienie ich spójności i aktualności poprzez hermetyzację wymaganych reguł biznesowych i logiki walidacji danych.

  • Klasy modelu nie odwołują się bezpośrednio do klas widoku ani widoku modelu i nie mają zależności od sposobu ich implementacji.

  • Klasy modelu zwykle zapewniają zdarzenia powiadamiania o zmianie właściwości i kolekcji za pośrednictwem interfejsów INotifyPropertyChangedi INotifyCollectionChanged. Pozwala to na łatwe wiązanie danych w widoku. Klasy modelu, które reprezentują kolekcje obiektów, zwykle pochodzą z ObservableCollection<T>klasy.

  • Klasy modelu zazwyczaj zapewniają walidację danych i raportowanie błędów za pośrednictwem interfejsów IDataErrorInfolub INotifyDataErrorInfo.

  • Klasy modelu są zwykle używane w połączeniu z usługą lub repozytorium, które hermetyzuje dostęp do danych i buforowanie.

Dom
źródło
18

Napisałem to mniej więcej jako „zwykły angielski”, jak mogę sobie wyobrazić w tej serii na MVVM . W szczególności ten diagram jest prawdopodobnie najprostszym, krótkim wyjaśnieniem.

Biorąc to pod uwagę, „modelem” są zasadniczo dane lub reguły biznesowe. Naprawdę nie powinien wiedzieć, jak i gdzie będzie używany, a zwłaszcza nie, która technologia będzie go używać. „Model” jest rdzeniem aplikacji - i nie powinien martwić się o to, czy aplikacja jest WPF, Silverlight, Windows Forms, ASP.NET itp. - jest po prostu „sobą” w czystej postaci.

„Widok” to część całkowicie związana z technologią. W MVVM najlepiej byłoby, gdyby widok był prawie w 100% XAML, ponieważ zapewnia to ogromne korzyści w zakresie elastyczności.

Jednak musi istnieć coś, co przetłumaczy informacje z Modelu na jakąś formę, w której będzie to możliwe do wykorzystania przez daną technologię - w tym miejscu do gry wkracza ViewModel. Na przykład często „zawija” klasy modelu w „ViewModel” dla tych konkretnych danych, które obejmują polecenia (do uruchamiania logiki), implementacje INotifyPropertyChanged(do obsługi powiązań danych) itd. To wszystko - to most sprawia, że ​​Model użyteczne przez Widok.

Reed Copsey
źródło
Ok dzięki. Myślałem o modelu jak o obiektach, a ViewModel jako o metodach obsługi obiektów, tak aby widok był w stanie zrozumieć „obiekty” Modelu. Ale powiedziano mi, że to jest złe, że sam ViewModel też są obiektami. Myślę, że to jest właśnie to, co mnie naprawdę dezorientuje.
RKM
@Rosie: Zalecałbym przeczytanie (lub przynajmniej przejrzenie) mojej serii, którą zacytowałem. Napisałem to specjalnie, ponieważ jest kilka (prawie żadnych) artykułów na temat MVVM, które nie zakładają, że rozumiesz MVC lub MVP itp. To naprawdę przejście "krok po kroku";)
Reed Copsey
Uświadomienie sobie tego wymaga trochę wątkowania zombie ... Twój diagram mówi, że maszyna wirtualna zawiera „stan i logikę specyficzną dla aplikacji ” (moje podkreślenie). Czy to sugeruje, że uważasz, że maszyna wirtualna może / powinna zawierać logikę kontroli jakości danych? Powiązany RssWpfMVVM.csproj nie wydaje się mieć żadnej oczywistej kontroli jakości w swoich dwóch modelach widoku.
ruffin
1

Świetne wprowadzenie do MVVM można znaleźć w filmie Jasona Dolingera tutaj . Kiedy zaczynałem, trzymałem wideo ze sobą przez dłuższy czas, jest naprawdę przydatne.

Filipe Miguel
źródło
1
Link nie działa
ibrahim mahrir
1
@ibrahimmahrir ~ Zaktualizowałem łącze do działającego adresu URL. Pobieram teraz wideo.
InteXX
0

Zbudowanie ViewModelu, który prezentuje spójną fasadę na podstawowym modelu, może być dużo bardziej złożone niż się wydaje. W tym artykule na temat tworzenia obiektów ViewModel pokazano, jak zbudować ViewModel i ilustruje niektóre problemy, które mogą wystąpić, wraz z tym, co wygląda na rozsądne rozwiązania. Kiedy go przeczytałem, brakowało sekcji dotyczącej radzenia sobie ze zbiorami, ale nadal zawiera kilka interesujących punktów.

Sprotty
źródło