2013-01-09 19 views
6

Przeczytałem kilka artykułów, tutoriali i wpisów na blogu na temat wzorca MVVM. Jest jednak jedna rzecz, której nie rozumiem. Biorąc trzy "warstwy":Do czego służy model w MVVM?

  • model
  • widok
  • Widok modelu

ile mam rozumieć MVVM model zawiera "na surowo", na przykład dane nazwa i adres w przypadku klasy Student. Model widoku eksponuje właściwości do widoku reprezentującego dane modelu.

Przykład właściwości w modelu widoku

public string Name { 
get { return model.Name; } 
set { model.Name = value; } 
} 

przykład dla modelu

private string name; 

public string Name { 
get { return name; } 
set { name = value; } 
} 

Może to brzmieć nieco głupie, ale nie stworzy to nadmiarowość? Dlaczego muszę zachować nazwę w modelu i modelu widoku? Dlaczego nie należy całkowicie obsługiwać nazwy w modelu widoku?

+1

Bardzo dobrze postawione pytanie, nawiasem mówiąc: jasne, zwięzłe i zawiera przykładowy kod. – JDB

Odpowiedz

5

W takim prostym przykładzie odpowiedź brzmi "tak" (jest to zbyteczne). Ale prawdopodobnie strona będzie zawierała więcej niż jeden obiekt Modelu. Możesz mieć stan strony, a także wiele innych obiektów Modelu, które muszą być wszystkie śledzone. Odbywa się to w ViewModel.

Na przykład użytkownik może mieć dodatkowe informacje o zalogowanym użytkowniku wyświetlanym na pasku stanu, a także usługę uruchomioną w celu wykrycia zmian w pliku tekstowym.

Możesz także mieć formularz do edytowania obiektu Ucznia. Jeśli chcesz zweryfikować te zmiany, nie będziesz chciał bezpośrednio edytować obiektu Ucznia, dopóki modyfikacje nie zostaną zweryfikowane. W takim przypadku ViewModel może działać tymczasowo.

Uwaga na powyższym: To nie jest rzadkością w przypadku walidacji występuje w modelu, ale nawet wtedy będzie prawdopodobnie chcesz, aby użytkownik mógł wprowadzić nieprawidłowe wartości, podczas gdy w procesie edycji formularza. Na przykład, jeśli Twój model nie zezwala na wartość o zerowej długości w polu, nadal chcesz umożliwić użytkownikowi usunięcie wartości, przenieść się do innego pola (powiedzmy na przykład, aby go skopiować), a następnie powrócić do pola i zakończ edycję (wklej). Jeśli jesteś przywiązany bezpośrednio do Modelu, to logika walidacji może nie obsługiwać tego stanu "pomiędzy", "jeszcze nie zakończony", jak chcesz. Na przykład możesz nie chcieć atakować swojego użytkownika błędami walidacji, dopóki nie skończą i nie klikną "Zapisz".

Prawdopodobnie będziesz mieć obiekty poleceń w ViewModelu do obsługi kliknięć przycisków i tym podobnych. Są to obiekty specyficzne dla domeny, które byłyby bezużyteczne w modelu.

ViewModels są również przydatne, gdy trzeba filtrować lub tymczasowo "modyfikować" obiekty modelu, aby uzyskać coś użytecznego na ekranie. Na przykład możesz wyświetlić listę wszystkich użytkowników w systemie wraz z listą dziesięciu najlepszych wykonawców (aktualizowanych co 10 sekund). Możesz również wyświetlić listę raportów i wykres pokazujący całkowity wskaźnik wykorzystania itp. Filtrowanie, sortowanie i dostosowywanie tych danych będzie miało miejsce w ViewModelu.

Model, z drugiej strony, jest zazwyczaj tak czysty, jak to możliwe. Najlepiej, aby tylko POCOs (zazwyczaj) model dokładnie to, co jest w trwałej pamięci (bazy danych, lub co masz). Jeśli Twój magazyn trwały ma pola FirstName i LastName, to także twój model. Tylko w swoim ViewModelu mógłbyś je połączyć, aby uzyskać pole Nazwa ("Pierwszy" lub "Ostatni, Pierwszy" w zależności od potrzeb Widoku).

Na przykład:

namespace Model 
{ 
    public class Student 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 

    public class Class 
    { 
     public string Name { get; set; } 
     public float Score { get; set; } 
    } 
} 

namespace ViewModel 
{ 
    public class EditStudentRecordViewModel 
    { 
     private Model.Student _student; 
     private IEnumerable<Model.Class> _studentClasses; 

     /* Bind your View to these fields: */ 
     public string FullName 
     { 
      return _student.LastName + ", " + _student.FirstName; 
     } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public IEnumerable<Model.Class> PassingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score >= 78); 
      } 
     } 

     public IEnumerable<Model.Class> FailingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score < 78); 
      } 
     } 

     public void Save() 
     { 
      List<string> l_validationErrors = new List<string>(); 
      if (string.IsNullOrEmpty(this.FirstName)) 
       l_validationErrors.Add("First Name must not be empty."); 
      if (string.IsNullOrEmpty(this.LastName)) 
       l_validationErrors.Add("Last Name must not be empty."); 

      if (l_validationErrors.Any()) 
       return; 

      _student.FirstName = this.FirstName; 
      _student.LastName = this.LastName; 
      Model.Utilities.SaveStudent(_student); 
     } 
    } 
} 
5

Model jest wykresem obiektów, który zawiera logikę biznesową.

To miejsce, w którym zachowuje się zachowanie (sprawdzanie poprawności, obliczenia itp.).

ViewModel jest czymś, co modeluje interfejs użytkownika i jego interakcje.

Są różne i mają różne powody, dla których istnieją - punktem wzoru jest oddzielenie logiki wyświetlania od VVM (View and ViewModel) i całkowite rozdzielenie logiki biznesowej.

0

modelu w MVVM jest dokładnie taka sama jak w MVP lub MODEL2 MVC. Jest to część wzorców inspirowanych MVC, na którą nie mają wpływu wariacje na temat.

Model to warstwa zawierająca repozytoria, jednostki pracy, obiekty domeny/modelu, narzędzia mapowania danych, usługi i niektóre inne struktury. Wszystko to razem tworzy warstwę modelu, która zawiera całą domenową logikę biznesową dla konkretnej aplikacji.

Model nie jest pojedynczą instancją. Każdy, kto do ciebie zadzwoni, jest w tym pełen.

Określone zastosowania, dla których zaprojektowano MVVM, dotyczą sytuacji, w których nie można zmodyfikować ani warstwy modelu, ani widoku instancji, ani obu tych metod.

P.S. Jednak jeśli używasz instancji ViewModel zgodnie z dokumentacją ASP.NET MVC, to faktycznie NIE używasz MVVM. To tylko Model2 MVC z różnymi nazwami rzeczy (gdzie "viewmodels" są w rzeczywistości widokami, a "views" są szablonami). Oni trochę popsuły się, kiedy wprowadzili na rynek podobną do Railsów architekturę jako "MVC".

4

Model widok jest gdzie chcesz śledzić właściwości, które są specyficzne dla widzenia i nie jest to konieczne do modelu.

Weźmy twój model, załóżmy, że nazywa się Person.

A potem stworzyć model widok dla Person nazwie PersonViewModel, który wygląda tak:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 
} 

(Uwaga, możesz nie chcieć, aby odsłonić model tak bezpośrednio, ale to inna historia)

Teraz powiedzmy, że masz przycisk w widoku, który jest używany do zapisania instancji Person.Aby zapewnić lepsze wrażenia użytkownika (UX), chcesz włączyć przycisk tylko wtedy, gdy model faktycznie się zmienił. Więc wdrożyć INotifyPropertyChanged interface na klasie Person:

public class Person : INotifyPropertyChanged 
{ 
    ... 

Teraz mógłby narazić właściwość HasUnsavedChanges ze swoimi Person którym nieruchomość Enabled na przycisk zapisz wiązałby się, jednak, że logika ma nic do robić z tą osobą.

To gdzie model widok przychodzi Można by określić to widok specyficzne właściwości modelu widoku, tak jak poniżej:.

public class PersonViewModel 
{ 
    public Person Person { get; set; } 

    public bool HasUnsavedChanges { get; set; } 
} 

Następnie Twój widok modelu będzie subskrybować PropertyChanged event z INotifyPropertyChanged interfejs i przełącz właściwość HasUnsavedChanges w modelu widoku.

Następnie, jeśli powiązanie jest prawidłowo skonfigurowane, przycisk zapisu włącza/wyłącza po każdej zmianie w modelu, ale model nie ma żadnej logiki wiążącej go z widokiem.

Należy pamiętać, że trzeba również zaimplementować model INotifyPropertyChanged w modelu widoku, aby widok był pobierany po wprowadzeniu zmian w modelu widoku, do którego jest przypisany.

Ponownie, punkt działa jako most w celu ograniczenia logiki, która jest kombinacją właściwości modelu i właściwości widoku, które nie należą do modelu.

1

Zawsze postrzegałem modele jako "elementy konstrukcyjne" aplikacji. Zwykle są to samodzielne klasy o pewnych właściwościach, a może nawet elementarnej walidacji lub logice wyłącznie dla własnych właściwości.

Zobacz Modele z drugiej strony to moje rzeczywiste klasy aplikacji, które kończą się używaniem "bloków konstrukcyjnych" (modeli) podczas budowania i uruchamiania aplikacji. Robią rzeczy lubią wykonywać zaawansowaną walidację, przetwarza polecenia obsługi zdarzeń, każdy rodzaj logiki biznesowej itp

Należy zauważyć, że nie mieć narazić właściwości danego modelu w swoim ViewModel jak masz w Twój przykładowy kod. Jest to podejście typu "MVVM purist", ponieważ całkowicie oddziela ono twoją warstwę Model od warstwy View, jednak jest również całkowicie dopuszczalne, aby wystawić cały Model na Widok. Właśnie tego używam w większości małych projektów ze względu na prostotę i brak duplikacji kodu.

public MyModel CurrentModel 
{ 
    get { return _model; } 
    set 
    { 
     if (_model != value) 
     { 
      _model = value; 
      RaisePropertyChanged("CurrentModel"); 
     } 
    } 
} 

Jednak jeśli istnieją przypadki, w których potrzebne jest tylko kilka właściwości z modelu w widoku, lub jeśli projekt jest na tyle duża, gdzie będę chciał zachować warstwy całkowicie oddzielne, potem wystawiać mój modelu właściwości do widoku przez ViewModel, tak jak w przykładowym kodzie.