Wzorzec Model-View-ViewModel

Dzisiaj będzie trochę o wzorcach projektowych. Mianowicie o MVVM, który zaleca się stosować w przypadku projektów opartych na WPF. Przyznam się szczerze, że zanim zrozumiałem zasadę działania tego wzorca i jego implementację minęło trochę czasu… Jednak po kilku podejściach w końcu się udało i mogę śmiało pisać w MVVM ;). Zaznaczam jednak, że pisanie kodu zgodnie z tym wzorcem, czasami może nie być łatwe i niektóre problemy mogą prosić się o rozwiązanie ich standardowo w code-behind. Ja na przykład siedziałem cały dzień nad tym jak z poziomu kodu zamknąć okno w aplikacji… Do tej pory uczę się tego wzorca, więc na pewno znajdzie się masa rzeczy, które mogę robić źle, lub o których nie wiem. Przejdźmy jednak do rzeczy.

Czym są wzorce projektowe?

W dużym skrócie są to wzory tego, jak należy pisać aplikację. Wyobraźmy sobie, że pracujemy w jakimś zespole i tworzymy jakiś duży, skomplikowany projekt. Każdy ma swój styl pisania kodu, każdemu wygodniej jest pisać inaczej. Szybko okazałoby się, że… wszyscy pogubili się w bałaganie powstałym przez takie podejście. Do tego, to dopiero wierzchołek góry lodowej. Wyobraź sobie teraz jak taki kod konserwować, kiedy mało kto jest w stanie się szybko w nim połapać. Jak szukać błędów?

Właśnie dlatego powstały wzorce projektowe, właśnie dlatego należy się ich trzymać. W założeniu dzięki nim kod ma być znormalizowany, przejrzysty i uporządkowany, tak aby każdy standardowy programista mógł połapać się, co jest od czego, w projekcie którego sam nie pisał ;).

Co daje nam MVVM?

W założeniu ma gwarantować niezależność logiki aplikacji, od widoku gdzie wyświetlamy dane. Co za tym idzie, powinno łatwo być przenosić kod logiki aplikacji pomiędzy różnymi technologiami prezentacji. Łatwą zmianę tych widoków, oraz przeprowadzanie automatycznych testów kodu.

Implementacja wzorca

Na początku sam miałem z tym ogromny problem. Implementacja wzorca, bez użycia żadnego Frameworka jest strasznie skomplikowana, długa, nieintuicyjna – przynajmniej dla mnie. Przerzucając się kiedyś z C++ na C# stwierdziłem: Wow, jak tu wszystko uproszczono! Tym bardziej tak skomplikowane użycie wzorca wydawało mi się nie podobne do języka jakim jest C# i całej platformy .NET .

Z pomocą przychodzą Frameworki. Sam wybrałem Prism i przy jego użyciu zbudowałem pierwszą aplikację opartą na MVVM ;).

Trochę teorii

Zanim przystąpimy do prezentacji implementacji wzorca z użyciem Prism, przydałoby się trochę teoretycznego wprowadzenia. Tak, więc zaczynajmy:

Wzorzec MVVM zakłada podzielenie kodu programu na trzy części tj:

  • Model – Tutaj przechowywany jest kod z logiką biznesową. Tutaj dane są pobierane i przetwarzane.
  • View – Nasz widok. W przypadku WPF to po prostu kod *.xaml. Nie powinna znajdować się tutaj żadna logika aplikacji.
  • ViewModel – Tutaj umieszczamy wszystko co znajdowało się do tej pory w code-behind. Jest to pośrednik pomiędzy Modelem, a View. W istocie ViewModel jest czymś, co wystawia dane dla naszego View, poprzez właściwości.

Skoro wiemy już co jest od czego, przejdźmy dalej.

Instalacja Prism

Instalacja tego Frameworka jest bardzo prosta, wystarczy stworzyć nowy projekt WPF (lub otworzyć istniejący) i na dole w zakładce Package Manager Console wpisać Install-Package Prism.Mvvm. Po udanej instalacji, możemy przejść do dostosowania naszego projektu na potrzeby wzorca MVVM.

Tworzymy wymagane pliki

Tak jak pisałem wcześniej. Do poprawnego działania wzorca wymaga trzech części kodu(klas). Tak, więc stwórzmy je teraz.

View już mamy, jest to nasze okno MainWindow. Stwórzmy więc teraz dla niego ViewModel. W tym celu dodajmy do projektu nową klasę i nazwijmy ją MainWindowViewModel.

Konfigurujemy View

Przejdźmy teraz do kodu *.cs naszego View. Po czym podepnijmy tutaj nasz ViewModel:

I to by było generalnie na tyle, jeżeli chodzi o nasze View. Teoretycznie nie powinien tutaj pojawiać się już żaden inny kod, chociaż czasem może zajść taka potrzeba – tak czy siak, należy tego jak najbardziej unikać.

Konfigurujemy ViewModel

Teraz przejdźmy do naszego ViewModel’u. Aby klasa ta pełniła faktycznie taką funkcję, musi implementować interfejs BindableBase.

I co dalej?

No dobrze, mamy już nasze View i ViewModel. Jak ich użyć? Przedstawie to na przykładzie użycia zwykłego buttona i pobierania/ustawiania wartości TextBoxa. Przejdźmy więc do rzeczy:

Na początku przejdźmy do kodu xaml i wstawmy do niego jakiś przycisk i textBoxa. Kod powinien wyglądać tak(za wyjątkiem rozmieszczenia):

Najważniejszą rzeczą jest tzw. Binding, który wiąże nasz widok z właściwościami/komendami znajdującymi się w kodzie ViewModel.

Przejdźmy teraz do ViewModel’u. Najpierw zajmiemy się obsługą naszego przycisku. W code-behind do tego, aby wykonać jakiś kod po jego wciśnięciu wykorzystujemy zdarzenia. W przypadku wzorca MVVM, używa się komend. Która została już do naszego przycisku w View podpięta. Jej obsługa w ViewModel będzie wyglądała tak:

Tworzymy publiczną właściwość IComand o nazwie takiej samej jak nazwa komendy w View. Następnie w konstruktorze wpisujemy kod, który w przypadku wywołania komendy, wywoła kod znajdujący się w jakiejś funkcji. W tym przypadku funkcja nazywa się ClickButton();.

No dobrze, ale komendy to nie wszystko. Trzeba też jakoś wyświetlać dane np. w TextBlock’ach lub pobierać je z Texbox’ów itd… Jak tego dokonać?

Tak jak wcześniej, najpierw należy umieścić w View kod, który będzie bindował nasze dane z i do View. My już go tam umieściliśmy: Text=”{Binding MyTextBox}”. Następnie przechodzimy do ViewModel:

Jak widać wyżej. Najpierw musimy dodać prywatną właściwość _MyTextBox, która będzie pełniła funkcję swego rodzaju „bufora” dla wyświetlanych danych. Następnie tworzymy publiczną właściwość o takiej samej nazwie co ta w View. To co dzieje się w get chyba nie wymaga komentarza. W set natomiast wartość która jest przyjmowana przez pole MyTextBox jest przypisywana do właściwości _MyTextBox. Następnie za pomocą OnPropertyChanged(() => MyTextBox);, nasze View jest informowane o tym, że wartość pola MyTextBox zmieniła się, więc należy ją pobrać jeszcze raz. Z kolei w metodzie ClickButton() wyświetlana jest aktualna wartość pola MyTextBox, po czym przypisuje się do niej kolejną, następującą po sobie liczbę. Analogicznie postępuje się w przypadku np. TextBlock’a.

Z podstaw to byłoby chyba na tyle. Mam nadzieję, że obyło się bez błędów merytorycznych. Jeżeli są, dajcie znać w komentarzach 😉

14 przemyśleń nt. „Wzorzec Model-View-ViewModel

  1. Przyjemnie opisane.
    Sugeruję załączać prosty przykładowy projekt przy takich wpisach albo odniesienie do gita.

  2. Fajny post. Pierwsze co mnie urzeklo przy poznawaniu WPFa (po poznaniu WinForms) to wlasnie seperacja przy wsparciu wzorca MVVM. Mala uwaga – wlasciwie nie musiales tu nawet uzywac Prism, bo to co zrobiles obsluguje sam WPF. Wyjatkiem jest tu chyba bindowanie ICommand bo to jest jakos w samym WPF dziwnie zrobione i ja osobiscie np. korzystalem z MvvmLight tylko po to, zeby korzystac z ichniejszych komend.

    • Oczywiście, że da się bez – ale po co sobie utrudniać życie 😀 Sam właśnie też gubiłem się w tych komendach bez frameworka. Ja wybrałem Prism, ty MvvmLight. Kwestia gustu 😉
      Prism ma tą zaletę/wadę, że jest dosyć rozbudowany i posiada jeszcze sporo innych funkcji – póki co nie przydawały mi się. Jednak dopiero zaczynam przygodę z MVVM, więc kto wie co się jeszcze może zdarzyć 😀

    • Zauważyłem też ten problem. Występuje losowo na różnych podstronach… Jestem prawie pewny, że to wina hostingu. Planuję go zmienić – jednak zanim to nastąpi, tymczasowym rozwiązaniem problemu jest po prostu odświeżenie strony.

Możliwość komentowania jest wyłączona.