Model View ViewModel

by Florin 20. February 2010 10:14

Pentru multe tipuri de aplicatii, pattern-ul Model View ViewModel a devenit sinonim cu WPF. 

Istoric vorbind, MVVM se trage din MVP (Model-View-Presenter). In acest pattern, Modelul reprezinta efectiv datele din aplicatie, View-ul reprezinta UI-ul, iar Presenter-ul face legatura dintre cele doua. Practic Presenter-ul tine referinte atat catre Modele cat catre View-uri.

In 2004, Martin Fowler publica un articol despre un pattern pe care el il numea Presentation Model, similar cu MVP. Pattern-ul era inovator pentru ca decupla total partea de interfata de partea de cod. Spre deosebire de MVP, nu exista referinte dinspre partea de logica catre partea de UI. Chiar daca conceptul era inovator, in 2004 s-a dovedit un pic inaintea timpului sau pentru ca nu exista un framework sau o infrastructura care sa faca legatura intre partea de UI si partea de logica. Insasi Fowler isi exprima speranta ca va exista in curand un asemnea sistem.

Acest sistem este Windows Presentation Foundation. WPF a fost conceput din start cu posibilitatea de a implementa acest pattern in vizor. In timp ce WPF era dezvoltat de Microsoft, in paralel era folosit pentru dezvoltarea lui Expression Blend, folosind pattern-ul PM. In momentul in care a fost prezentat, a fost denumit Model View ViewModel, pe scurt MVVM.

Elementele care sunt indispensabile pentru implementarea MVVM sunt:

  • Databinding
  • Comenzi

Scopul lui MVVM este de a decupla perfect logica de interfata. Astfel interfata este ca un skin care se muleaza peste logica si este 100% schimbabila, pentru ca nu exista referinte hard-coded catre ea.

 

Caracteristici ale lui MVVM:

  1. Modelul reprezinta partea de date din aplicatie. Toate clasele de business (domain objects) fac parte din Model.
  2. Ideal, View-urile sunt doar ferestre sau user-control-uri XAML, fara cod in fisierul codebehind.
  3. Intre View-uri si ViewModel-uri exista o relatie de unu la unu, fiecare View are propria instanta de ViewModel. Pentru a realiza o separare clara intre logica si UI, functionalitatea se implementeaza in ViewModel. ViewModel-ul apeleaza clasa de business, daca este cazul.
  4. Un View are ViewModel-ul sau ca si DataContext. Toata afisarea se face prin databinding elementelor de interfata la proprietati din context.
  5. Pentru a executa logica din UI, se folosesc Commands.

Demo

Vom face o aplicatie demo simpla in care vom demonstra cum se foloseste MVVM. Sa consideram o aplicatie in care dorim sa introducem persoane intr-o anumita lista.

Partea de Model in aplicatia noastra este compusa dintr-o singura clasa, Persoana. 

public class Persoana
{
   public string Nume { get; set
; }

   public string Prenume { get; set
; }

   public string NumeIntreg
   {
      get
      {
         return Nume + " "
+ Prenume;
      }
   }
}

Partea de View este compusa dintr-o singura fereastra, AdaugarePersoaneView.xaml.

<Window x:Class="MVVM.AdaugarePersoaneView"
xmlns
=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:mvvm="clr-namespace:MVVM"
Title="Adaugare persoane" Height="300" Width
="300">
<Window.Resources
>
<mvvm:AdaugarePersoaneViewModel x:Key
="model"/>
</Window.Resources
>
<Grid DataContext="{StaticResource model
}">
<StackPanel
>
<ItemsControl ItemsSource="{Binding Persoane}" DisplayMemberPath
="NumeIntreg" />
<TextBox Text="{Binding Nume}" Width
="150" />
<TextBox Text="{Binding Prenume}" Width
="150" />
<Button Content="Adauga" Width="100" Command="{Binding AdaugaPersoana
}" />
</StackPanel
>
</Grid
>
</
Window>

In fereastra avem o lista care afiseaza persoanele adaugate, doua textbox-uri (pentru numele si prenumele persoanei ce urmeaza sa fie adaugata, si un buton, pentru adaugarea persoanei in lista). Dupa cum se poate observa, la sectiunea de resurse se defineste o instanta de model, care este setata ca si DataContext. Modelul arata astfel:

public class AdaugarePersoaneViewModel
{
   public
AdaugarePersoaneViewModel()
   {
      Persoane = new ObservableCollection<Persoana
>();
      AdaugaPersoana = new DelegateCommand
(AdaugaPers);
   }

   public ObservableCollection<Persoana> Persoane { get; set
; }

   public string Nume { get; set
; }

   public string Prenume { get; set
; }

   public DelegateCommand AdaugaPersoana { get; set
; }
  

  
private void AdaugaPers()
   {
      Persoana pers = new Persoana
()
      { 
         Nume = this
.Nume,
         Prenume = this
.Prenume
      };
     
Persoane.Add(pers);
   } 

}

Se poate vedea ca niciunde in cod nu sunt accesate controalele, acestea neavand un atribut x:Name, valoarea lor transmitandu-se prin data binding. Nu exista nici un eveniment de Click pentru buton. In schimb in Model este definita comanda AdaugaPersoana, care este asociata butonului tot prin binding. La executia comenzii, se apeleaza metoda AdaugaPers() ce creeaza o persoana in functie de proprietatile Nume si Prenume (ce isi primesc valoarea prin binding din interfata), dupa care aceasta este adaugata la lista de persoane. 

Ultimul lucru pe care trebuie sa-l definim este clasa DelegateCommand.

public class DelegateCommand: ICommand
{
   private Action
_Executed;

   public DelegateCommand(Action
executed)
   {
      _Executed = executed;
   }

   #region
ICommand Members

   public bool CanExecute(object
parameter)
   {
      return true
;
   }

   public
event EventHandler CanExecuteChanged;

   public
void Execute(object parameter)
   {
      _Executed();
   }

   #endregion
}

Pentru mai multe detalii despre comenzi, cititi articolul dedicat acestora.

Se poate vedea ca este necesar sa scriem un pic mai mult cod decat am face-o de obicei pentru o asemenea functionalitate simpla. Este evident ca MVVM nu se preteaza in orice situatie. MVVM nu se recomanda a fi folosit in aplicatii mici sau in aplicatii UI intensive (unde majoritatea efortului reprezinta partea de design sau animatii). Aplicatiile data-driven sau cele care modeleaza anumite procese (business) sunt domeniul unde MVVM straluceste. Iata cateva avantaje pe care MVVM le ofera:

  1. Decupland total partea de UI de partea de logica, putem foarte usor aplica Unit testing pe core. In cazul unei aplicatii cu procese complexe, acest lucru este de o importanta cruciala.
  2. WPF a mers din start pe ideea ca designerii si programatorii trebuie sa poata sa lucreze cat mai independent unii de altii (de unde si conceptul de look-less controls si templates). MVVM duce aceasta idee chiar mai departe.  Designerul lucreaza pe View iar programatorul pe ViewModel.
  3. Databinding poate sa fie greu de folosit, pentru ca nu avem acces la intelisense. Dar daca se respecta guide-lines-urile Microsoft si modelul este declarat in sectiunea de resurse a View-ului, designerul poate sa faca binding pe obiectele din interfata cu ajutorul lui Blend, care ii va expune vizual proprietatile DataContext-ului intr-o lista, facand aceasta operatiune foarte usoara.

Tags:

Comments

Add comment

Nume

Email

Website

biuquote
Loading



Powered by BlogEngine.NET 1.5.0.7