<p>Kolejnym wzorcem złożonym jest Model-View-ViewModel . Jest on najmłodszym (najnowszym?) wzorcem z trójcy do której należą jeszcze MVC i MVP. Pierwotnie miałem napisać o nim, jak Pan Bóg przykazał, w trzecim wpisie (żeby chronologia się zgadzała 😉 ) ,po przemyśleniach wskoczył jednak na drugie miejsce z dwóch powodów. Po pierwsze: Jego koncepcja różni się, według mnie, dosyć mocno od MVC (choć może to tylko złudzenie WPF’em), co pozwoli świeżo spojrzeć na temat, a także pisać o MVP w trochę innym podejściu. I po drugie: Jako, że HardTraining jest pisany z wykorzystaniem WPF’a, MVVM wydał mi się być dzisiaj odpowiednim tematem 🙂 .</p>
<p>Zadanie jakie stawiane jest przed omawianym wzorcem, jest takie same jak dla każdego członka rodziny View-Model: separacja kodu w zależności od pełnionej funkcji. I jak w każdym innym wzorcu z tej rodziny, mamy trzy warstwy :</p>
<ul>
<li><b>Warstwę modelu:</b> jest ona bliźniaczo podobna do jej odpowiedników w MVC i MVP</li>
<li><b>Warstwę widoku:</b> ta służy identycznym celom, co widoki w pozostałych wzorcach.</li>
<li><b>Warstwę widoku modelu:</b> i tu już jest znacząca różnica. Widok modelu, owszem, stanowi pewnego rodzaju łącznik między sąsiednimi warstwami ale robi to w dosyć specyficzny sposób. Mianowicie „przygotowuje” model do stanu w jakim może on być przedstawiony użytkownikowi. Innymi słowy nakłada puder 😉</li>
</ul>
<p>Prawdziwą inność MVVM manifestuje w sposobie wiązania warstwy widoku i warstwy modelu. Ale zacznijmy od początku. MVVM został zaprojektowany (choć może w przypadku wzorców powinno się używać określenia „wynaleziony”) przez Microsoft, jako wsparcie dla implementacji aplikacji tworzonych w WPF’ie. Myk polega na tym, że WPF kładzie mocno nacisk na programowanie sterowane zdarzeniami. Jednocześnie możliwe jest, w prosty sposób, powiązanie kodu z interfejsem użytkownika unikając jednak sztywnych połączeń. Do tego celu wykorzystujemy właśnie MVVM.</p>
<img src="/static/img/blog/mvvm.png" alt="" class=" postImage" />
<p>Trochę więcej o warstwach, przez pryzmat HardTraining:Model, jak już wspominałem wcześniej, to warstwa odpowiedzialna za logikę biznesową, oraz dane. Może być to obraz bazy (klasy POCO), lub po prostu reprezentacja domenowa. W HardTraining dane to klasy POCO dla modelu bazy w Entity Framework, natomiast wiadomo, wszelkie serwisy itd. stanowią, jak to zwykle bywa obraz domeny aplikacji.</p>
<p>Widok w WPF, pisany jest przy użyciu języka znacznikowego XAML, „fizycznie” jest też możliwość by posiadał tzw. code behind, czyli kod pisany w C#, na przykład do obsługi zdarzeń, jednak aby wykorzystać wszystkie zalety wzorca MVVM, widok powinien zawierać tylko XAML. W HardTraining na razie ta sztuka nie do końca mi się udaje, bo w związku z tym, że poszczególne warstwy są w osobnych projektach, staram się żeby poszczególne elementy wiedziały o sobie możliwie jak najmniej. Chcąc otworzyć jakiś widok, wysyłam wiadomość, za pomocą Messengera – implementacji wzorca Mediator, dostarczanej wraz z frameworkiem MVVM Light – której odbiorcą jest widok. Nie jest to jednak najlepszy sposób, więc na mojej liście „to do” projektu pojawił się kolejny problem do rozwiązania 🙂</p>
<p>Widok modelu stanowi najciekawszy element układanki. Na jeden ViewModel może przypadać kilka widoków. VM zna model, i jego zadaniem jest pobranie z niego informacji by móc przedstawić je widokowi. W jaki sposób? Najefektywniej jest wykorzystać (oczywiście mówiąc o „czystym” WPF – frameworki takie jak MVVM Light, wprowadzają rozwinięcia idei, o czym napiszę w którymś z przyszłych postów) mechanizm bindowania danych (data binding), który pozwala w łatwy sposób na połączenie publicznej właściwości widoku modelu z widokiem. Takie bindowanie może działać tylko w jedną stronę (albo od użytkownika do VM albo odwrotnie), ale także w obie strony. Co więcej nie wymaga to żadnego kodu C# w widoku. I właśnie w taki sposób realizuje to w moim projekcie, jednocześnie korzystając z rozwiązań dostarczanych w MVVM Light.</p>
<p>Na zakończenie screen pokazujący warstwy w HardTraining:</p>
<img src="/static/img/blog/htMvvm.png" alt="" class=" postImage" />