Co to jest MVVM?
Aplikacje MAUI platformy .NET, które nie korzystają z maszyny MVVM, zwykle mają więcej kodu w swoich plikach za pomocą kodu. Pliki za pomocą kodu w programie .NET MAUI są zgodne z tym wzorcem: {something}.xaml.cs. Większość kodu w pliku za pomocą kodu zwykle kontroluje zachowanie interfejsu użytkownika. Zachowanie interfejsu użytkownika może obejmować dowolny element, który występuje w interfejsie użytkownika, na przykład zmiana koloru lub tekstu. Ponadto może zawierać wszystko, co się dzieje z powodu interfejsu użytkownika, w tym programy obsługi kliknięć przycisków.
Jednym z problemów z tym podejściem jest to, że trudno jest napisać testy jednostkowe względem plików z kodem. Pliki kodu często zakładają, że stan aplikacji tworzony przez analizowanie kodu XAML lub nawet tworzony przez inne strony. Te warunki są trudne do obsługi w module uruchamiającym testy jednostkowe, które mogą nawet nie być uruchomione na urządzeniu przenośnym, nie mówiąc już o interfejsie użytkownika. Dlatego testy jednostkowe rzadko mogą testować zachowania interfejsu użytkownika w tych plikach.
Ale oto, gdzie wzorzec MVVM jest przydatny. W przypadku poprawnego użycia wzorzec MVVM rozwiązuje te problemy, przenosząc większość logiki zachowania interfejsu użytkownika do klas z możliwością testowania jednostkowego, które są nazywane modelami widoków. Wzorzec MVVM jest najczęściej używany z platformami obsługującymi powiązanie danych. Dzieje się tak dlatego, że za pomocą interfejsu MAUI platformy .NET można powiązać każdy element interfejsu użytkownika z elementem viewmodel
i wyeliminować lub prawie wyeliminować kod w widoku lub kodzie.
Jakie są części aplikacji MVVM?
viewmodel
Chociaż element jest unikatową częścią wzorca MVVM, wzorzec definiuje również część modelu i część widoku. Definicje tych części są zgodne z innymi typowymi wzorcami, takimi jak Model-View-Controller (MVC).
Co to jest model?
W aplikacji MVVM termin model jest używany do oznaczania danych i operacji biznesowych. Model nie wiąże się z prezentacją użytkownika aplikacji.
Przydatną regułą do określania, jaki kod należy do modelu, jest to, że powinien być przenośny na różnych platformach. Z aplikacji mobilnej do interfejsu internetowego, a nawet programu wiersza polecenia, używając tego samego modelu we wszystkich wystąpieniach. Nie ma związku z tym, jak informacje są wyświetlane użytkownikowi.
Jeśli myślisz o aplikacji HR z naszego scenariusza, model może zawierać klasę Employee
i klasę Department
, która przechowuje dane i logikę tych jednostek. Model może również zawierać takie elementy jak klasa, która przechowuje logikę EmployeeRepository
trwałości. Niektóre inne wzorce projektowe oprogramowania uwzględniają takie elementy, jak repozytoria , niezależnie od modelu. Jednak w kontekście MVVM często odnosimy się do dowolnej logiki biznesowej lub danych biznesowych w ramach modelu.
Oto dwa przykłady modelu w języku C#:
public class Employee
{
public int Id { get; }
public string Name { get; set; }
public Employee Supervisor { get; set; }
public DateTime HireDate { get; set; }
public void ClockIn() { ... }
}
public class EmployeeRepository
{
public IList<Employee> QueryEmployees() { ... }
...
}
Co to jest widok?
Widok kodu steruje elementami, które bezpośrednio wchodzą w interakcję z użytkownikiem, takimi jak kontrolki, takie jak przyciski i pola wprowadzania, a także inne czysto wizualne elementy, takie jak motywy, style i czcionki.
W programie .NET MAUI nie trzeba pisać żadnego kodu w języku C#, aby samodzielnie wygenerować widok. Zamiast tego często definiuje się widoki według plików XAML. Oczywiście istnieją sytuacje, które powodują wywołanie niestandardowej kontrolki użytkownika, w której tworzysz własny widok za pomocą kodu.
Co to jest viewmodel
?
To prowadzi nas z powrotem do viewmodel
. Jest viewmodel
to pośrednik między naszą logiką biznesową (model) a naszymi widokami (UI).
Zastanów się, co viewmodel
może zrobić dla aplikacji HR. Załóżmy, że istnieje widok, który wyświetla dostępny czas urlopowy pracownika i chcesz, aby saldo urlopu było wyświetlane jako "2 tygodnie, 3 dni, 4 godziny". Jednak logika biznesowa w modelu zapewnia tę samą wartość co 13,5 dni, czyli liczbę dziesiętną reprezentującą łączną liczbę dni w 8-godzinnym dniu roboczym. Model obiektów może wyglądać podobnie do poniższej listy:
Model —
Employee
klasa zawierająca metodę:public decimal GetVacationBalanceInDays() { //Some math that calculates current vacation balance ... }
ViewModel —
EmployeeViewModel
klasa, która ma właściwość podobną do następującej:public class EmployeeViewModel { private Employee _model; public string FormattedVacationBalance { get { decimal vacationBalance = _model.GetVacationBalanceInDays(); ... // Some logic to format and return the string as "X weeks, Y days, Z hours" } } }
View — strona XAML zawierająca pojedynczą etykietę i przycisk zamknięcia. Etykieta ma powiązanie z właściwością
viewmodel
:<Label Text="{Binding FormattedVacationBalance}" />
Następnie wystarczy
BindingContext
, że strona zostanie ustawiona na wystąpienie klasyEmployeeViewModel
.
W tym przykładzie model zawiera logikę biznesową. Ta logika nie jest powiązana z wyświetlaniem wizualizacji ani urządzeniem. Można użyć tej samej logiki dla urządzenia przenośnego lub komputera stacjonarnego. Widok nie zna nic z logiki biznesowej. Kontrolki widoku, takie jak etykieta, wiedzą, jak uzyskać tekst na ekranie, ale nie obchodzi, czy jest to saldo urlopu czy losowy ciąg. Zna viewmodel
trochę obu światów, więc może działać jako pośrednik.
Co ciekawe, sposób viewmodel
osiągnięcia jest pośrednikiem: uwidacznia właściwości, z którymi może wiązać się widok. Właściwości publiczne to jedyny sposób zapewniania viewmodel
danych. To prowadzi nas do tego, dlaczego jest to nazywane .viewmodel
"Model" w MVVM reprezentuje strukturę, dane i logikę procesów biznesowych, viewmodel
reprezentuje strukturę, dane i logikę wymaganą przez widok.
W jaki sposób widok działa z elementem viewmodel
?
Gdy przyjrzysz się relacji z viewmodel
modelem, jest to standardowa relacja między klasami. Obiekt viewmodel
ma wystąpienie modelu i uwidacznia aspekty modelu w widoku za pomocą właściwości. Ale jak widok pobiera i ustawia właściwości w viewmodel
obiekcie ? viewmodel
W jaki sposób widok aktualizuje kontrolki wizualizacji przy użyciu nowych wartości? Odpowiedź to powiązanie danych.
viewmodel
Właściwości są odczytywane w momencie, gdy obiekt jest powiązany z widokiem. Jednak powiązanie nie ma możliwości poznania, czy viewmodel
właściwości elementu zmienią się po zastosowaniu powiązania do widoku. viewmodel
Zmiana elementu nie powoduje automatycznego propagowania nowej wartości za pomocą powiązania do widoku. Aby zaktualizować z viewmodel
widoku do widoku, viewmodel
należy zaimplementować System.ComponentModel.INotifyPropertyChanged
interfejs.
Interfejs INotifyPropertyChanged
deklaruje jedno zdarzenie o nazwie PropertyChanged
. Przyjmuje on pojedynczy parametr, nazwę właściwości, która zmieniła jego wartość. System powiązań używany w programie .NET MAUI rozumie ten interfejs i nasłuchuje tego zdarzenia. Gdy właściwość zmienia się na viewmodel
obiekcie i zgłasza zdarzenie, powiązanie powiadamia element docelowy zmiany.
Zastanów się nad tym, jak działa to w aplikacji HR z pracownikiem viewmodel
. Obiekt viewmodel
ma właściwości reprezentujące pracownika, takie jak nazwa pracownika. Obiekt viewmodel
implementuje INotifyPropertyChanged
interfejs i gdy Name
właściwość ulegnie zmianie, zgłasza PropertyChanged
zdarzenie, w następujący sposób:
using System.ComponentModel;
public class EmployeeViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private Employee _model;
public string Name
{
get {...}
set
{
_model.Name = value;
OnPropertyChanged(nameof(Name))
}
}
protected void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Widok opisujący szczegóły pracownika zawiera kontrolkę etykiety powiązaną z właściwością viewmodel
pracownika Name
:
<Label Text="{Binding Name}" />
Name
Gdy właściwość zmieni się w viewmodel
obiekcie , PropertyChanged
zdarzenie jest wywoływane z nazwą tej właściwości. Powiązanie nasłuchuje zdarzenia, a następnie powiadamia etykietę o Name
zmianie właściwości. Następnie właściwość etykiety zostanie zaktualizowana Text
o najnowszą wartość.