Co to jest MVVM?

Ukończone

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).

Diagram ilustrujący, jak model widoku jest pośrednikiem między modelem a widokiem.

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:

  • ModelEmployee klasa zawierająca metodę:

    public decimal GetVacationBalanceInDays()
    {
        //Some math that calculates current vacation balance
        ...
    }
    
  • ViewModelEmployeeViewModel 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 klasy EmployeeViewModel.

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 viewmodelobiekcie ? viewmodel W jaki sposób widok aktualizuje kontrolki wizualizacji przy użyciu nowych wartości? Odpowiedź to powiązanie danych.

viewmodelWłaściwości są odczytywane w momencie, gdy obiekt jest powiązany z widokiem. Jednak powiązanie nie ma możliwości poznania, czy viewmodelwł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ą viewmodelpracownika Name :

<Label Text="{Binding Name}" />

Name Gdy właściwość zmieni się w viewmodelobiekcie , 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ść.

Sprawdź swoją wiedzę

1.

Deweloper pracuje nad aplikacją .NET MAUI i chce zaimplementować wzorzec MVVM. Utworzyli model dla danych biznesowych i operacji oraz widok interakcji z użytkownikiem. Co należy utworzyć obok, aby działać jako pośrednik między modelem a widokiem?

2.

Zespół opracowuje aplikację mobilną przy użyciu interfejsu MAUI platformy .NET i chce mieć pewność, że ich logika biznesowa jest przenośna na różnych platformach. Gdzie należy umieścić tę logikę biznesową we wzorcu MVVM?