ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 15
Abonament PDF

MVVM în Windows Phone 8

Cosmin Stirbu
iOS Software Developer
@Fortech



DIVERSE

Şablonul de proiectare Model-View-ViewModel (MVVM) defineşte trei componente principale: Model, View şi ViewModel:

Model: Business domain (logica ce ţine de domeniul aplicaţiei, accesul la date, entităţi),

View: Interfaţa cu utilizatorul (în Windows Phone - PhoneApplicationPage),

ViewModel: "Modelul View-ului" - abstractizare a View-ului ce intermediază comunicarea dintre View şi Model.

Una dintre diferenţele majore între Model-View-Controller şi MVVM este că un obiect de tipul ViewModel nu păstrează o referinţă la obiectul de tip View. Obiectul View se leagă (binding) la proprietăţile obiectului ViewModel care în schimb expune datele conţinute în model şi alte stări specifice View-ului. Mecanismul de binding asigură că, atunci când proprietăţile din ViewModel se modifică, cele din View se actualizează automat şi vice-versa. Când utilizatorul apasă un buton, o comandă se execută în ViewModel, View-ul nu modifică niciodată în mod direct entităţile din model. Clasele View nu ştiu de existenţa claselor din model în timp ce clasele ViewModel şi modelul nu ştiu de existenţa claselor View. În acest fel View-ul este pur și simplu un client (consumer) al obiectelor ViewModel, ele putând fi foarte ușor înlocuite cu clase de test pentru ViewModel.

Cum aplicăm MVVM în Windows Phone 8?

MVVM Light este un instrument foarte popular dezvoltat şi întreţinut de Laurent Bugnion, fiind folosit pentru a dezvolta cu rapiditate aplicaţii MVVM în WPF, Silverlight şi Windows Phone. Acest toolkit ne ajută să sepărăm View-ul de Model pentru a crea aplicaţii mai curate şi mai uşor de întreţinut şi de extins, stratul dedicat interfeţei cu utilizatorul este cât se poate de subţire iar astfel aplicaţiile dezvoltate fiind uşor de testat automat.

Sursa: blogs.msdn.com/b/tims/archive/2010/11/02/kung-fu-silverlight-architectural-patterns-and-practices-with-mvvm-and-ria-services.aspx

Una dintre componentele oferite este clasa ViewModelBase pe care fiecare clasă ViewModel a aplicaţiei noastre o poate extinde fără a fi nevoită să implementeze interfaţa INotifyPropertyChanged (pentru a notifica View-ul la schimbarea valorii unei proprietăţi). În general, într-o aplicație Windows Phone 8, fiecărei Pagini îi va corespunde un obiect ViewModel ce va extinde clasa ViewModelBase. Un alt mare avantaj al clasei ViewModelBase este expunerea proprietăţii IsInDesignMode, proprietate ce ne permite să verificăm dacă suntem în Expression Blend sau în Visual Studio Designer şi să oferim "design data" cu care designerul poate lucra. Suntem nevoiţi să facem acest lucru, deoarece atât Blend cât şi Visual Studio Designer nu permit operaţii în reţea sau conexiuni la baze de date.

În general, o abordare posibilă şi des întâlnită este de a expune toate obiectele noastre ViewModel ca proprietăţi folosind clasa oferită de MVVM Light numită ViewModelLocator. În această clasă putem folosi un IoC Container preferat (sau SimpleIoc inclus în MVVM Light) pentru a crea obiectele ViewModel şi pentru a injecta dependenţe în acestea (de exemplu o interfaţă care expune metode pentru a manipula diferite entităţi din model).

Obiectul de tip ViewModelLocator poate fi adăugat în resursele aplicaţiei în App.xaml şi folosit apoi în fiecare pagină pentru a seta DataContext-ul acesteia la ViewModel-ul corespunzător expus în ViewModelLocator.

ViewModelLocator adăugat în mod automat la crearea unui proiect ca resursă în App.xaml:


< Application 
 ...
 xmlns:vm="clr-namespace:{Default Namespace}.ViewModel"
 ...>
  < Application.Resources>
    < ResourceDictionary>
    < !-- Global View Model Locator -->
    < vm:ViewModelLocator x:Key="Locator"
      d:IsDataSource="True" />
      ...
   < /ResourceDictionary>
  < /Application.Resources>
< /Application>

Putem seta ca DataContext pentru Pagina (View) un obiect ViewModel expus ca proprietate în ViewModelLocator pentru a realiza apoi "binding" între proprietățile obiectului ViewModel și Pagină (View). Acest lucru îl putem face fie direct în .xaml sau folosind Blend.

Dacă vrem de exemplu să afișăm conținut într-un obiect TextBlock, tot ce trebuie să facem este să legăm proprietatea Text de o proprietate de tip string în obiectul ViewModel nefiind nevoiți să scriem cod de UI (cunoscut drept code-behind) pentru a actualiza textul din TextBlock-ul respectiv. Legarea o putem face atât în codul XAML cât și în Blend.

string _textProperty
public string TextProperty
{
  get
  {
     return _textProperty;
  }
  set
  {
  if (_textProperty != value)
  {
    _textProperty = value;
    RaisePropertyChanged("TextProperty");
   }
  }
}

Apelul metodei moștenite din ViewModelBase RaisePropertyChanged asigură actualizarea UI-ului de fiecare dată când valoarea proprietății se schimbă.

Codul de legare arată astfel:

< TextBlock Text="{Binding TextProperty}"
 Style="{StaticResource PhoneTextNormalStyle}"
 HorizontalAlignment="Center"
 VerticalAlignment="Center"
 TextAlignment="Center"
 TextWrapping="Wrap"
 FontSize="40" / > 

Practic orice proprietate a unui element de UI poate fi legată de o proprietate din obiectul ViewModel fără a fi nevoiți să scriem cod de UI. De exemplu putem lega proprietatea ItemSource a unui obiect ListBox de o propritetate de tip List din ViewModel și apoi putem configura un ItemTemplate pentru ListBox care va avea ca DataContext obiectul de tip T care conceptual vorbind este și el la rândul său un ViewModel (sau ItemViewModel).

Cum comunică View-ul cu ViewModel-ul?

MVVM Light oferă clasa EventToCommand ce extinde clasa Behavior și ce permite legarea unei comenzi de un eveniment de pe interfața cu utilizatorul. Astfel la apariția unui eveniment putem executa direct codul din ViewModel fără a scrie deloc cod de UI. În ViewModel expunem o proprietate de tipul RelayCommand pe care cu ajutorul clasei EventToCommand o putem lega de orice eveniment.

Evenimentul Click al unui buton este legat de comanda ButtonPressed:

// Button Pressed
public RelayCommand ButtonPressed
{
  get
  {
    return new RelayCommand(() =>
    {
    Console.WriteLine("Button Pressed");
    });
  }
} 

Merită menționat că putem transmite și parametri atunci cînd folosim EventToCommand: de exemplu, putem transmite textul dintr-un TextBox, iar pentru aceasta am expune o proprietate de tipul RelayCommand. EventToCommand poate fi atașat oricărui element de UI, chiar și Paginii, apelând o comandă atunci când pagina s-a încărcat (evenimentul Loaded) pentru a face un request HTTP la un serviciu Web.

Cum comunică ViewModel-ul cu View-ul?

În afara mecanismului de binding ViewModel-ul poate comunica cu View-ul prin mecanisme precum Behavior, Messenger sau prin folosirea unor interfețe pe care View-ul le va implementa, după care va fi injectat în ViewModel.

Extinzând clasa Behavior putem declara proprietăți DependencyProperty împreună cu proprietăți normale pe care le putem lega de proprietăți din ViewModel și care atunci când își schimbă valoarea pot executa cod de UI. Avantajele obiectelor Behavior sunt: reutilizarea cu ușurință, folosirea în Blend și posibilitatea de a muta codul din View.

MVVM Light oferă o clasă Messenger folosită de diferite obiecte pentru a comunica în cadrul aplicației fără ca acestea să știe cu cine comunică, astfel folosind această clasă cuplajul între obiectele care comunică este redus. Mesajele pot conține date simple sau obiecte complexe. Această clasă poate fi des folosită pentru a permite obiectelor ViewModel să comunice între ele sau pentru a permite obiectelor ViewModel să comunice cu obiectele View.

O altă abordare este crearea unor interfețe ce vor fi implementate de View. De exemplu dacă în View trebuie să arătăm un mesaj (un dialog) putem crea o interfață ce expune acele metode după care o implementăm în View și o injectăm în ViewModel (putem obține o referință la ViewModel-ul corespunzător folosind proprietatea DataContext).

Merită menționat că abordarea preferată este extinderea clasei Behavior, deși MVVM nu specifică în mod direct, este de înțeles că atât timp cît codul din Pagini este redus, aplicația este cu atât mai ușor de testat. Un dezavantaj al Behavior -urilor este că acestea nu sunt disponibile pentru Windows 8, făcând astfel portabilitatea aplicațiilor puțin mai dificilă dar sunt librării care oferă clase similare claselor Behavior .

Probleme des întâlnite și soluțiile lor

Una dintre problemele des întâlnite este navigarea: de unde se face navigarea către o altă pagină și cum? Soluția este relativ simplă - creăm o interfață care să expună metodele necesare navigării, o implementăm într-o clasă dedicată apoi o injectăm în obiectele ViewModel din care dorim să realizăm navigarea.

O altă problemă este disponibilitatea datelor la momentul designului - abordarea recomandată este crearea unor interfețe pentru managerii de date (clasele în care avem logică de acces la date, persistență, etc) și implementarea acestora în două clase diferite: una pentru momentul designului, și una ce va fi folosită la momentul rulării aplicației. Folosind proprietatea IsInDesignMode putem înregistra în containerul IoC clasa corespunzătoare ce va fi mai apoi injectată în ViewModel. Această funcționalitate împreună cu Blend oferă posibilitatea formării echipelor de designeri și developeri care să lucreze relativ independent.

Din nou clasele Behavior permit crearea și tranziția între diferite stări ale unei Pagini sau declanșarea unor animații, acest lucru fiind posibil fără a fi nevoiți să scriem cod de UI. Clase Behavior precum DataStateBehavior sau GoToStateAction permit acest lucru.

Din păcate, în Windows Phone 8, nu putem face în mod direct binding între Application Bar și comenzi din ViewModel. Spre deosebire de Windows 8, unde acest lucru este posibil. Astfel în aceste situatii suntem nevoiți să scriem cod de UI, să ascultăm evenimentele butoanelor de pe Application Bar și apoi să exectuăm manual comenzile din ViewModel. Dacă nu dorim să facem aceasta, și de obicei nu dorim, putem folosi librăria AppBarUtils care oferă clase Behavior, Trigger și Action ce permit legarea cu comenzi și diferite proprietăți.

Concluzii

Șablonul MVVM este foarte popular în rândul dezvoltatorilor de aplicații Windows Phone, acesta permite dezvoltarea unor aplicații ușor de menținut, îmbunătățit, testat și de ce nu, cu o interfață grafică ușor de creat (Blend). Componentele definite de șablon au responsbilități bine definite iar cuplajul este redus pe cât de mult posibil. Dacă atunci când șablonul a fost introdus, implementarea acestuia părea destul de greoaie, necesitând multe linii de cod, în perioada recentă librăriile și instrumentele disponibile fac implementarea acestui șablon ușoară și interesantă.

Referințe

MVVM Light www.galasoft.ch/mvvm/

msdn.microsoft.com/en-us/magazine/jj651572.aspx

appbarutils.codeplex.com/

winrtbehaviors.codeplex.com/

vimeo.com/53068482

channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2264

outcoldman.com/en/blog/show/308

blogs.msdn.com/b/tims/archive/2010/11/02/kung-fu-silverlight-architectural-patterns-and-practices-with-mvvm-and-ria-services.aspx

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects