Použití modelu viewmodel

Dokončeno

Po seznámení s komponentami, které tvoří model Model-View-ViewModel (MVVM), pravděpodobně jste zjistili, že model a zobrazení byly snadno definovat. Pojďme se podívat, jak model viewmodel používat, abychom lépe definovali jeho roli v modelu.

Zveřejnění vlastností pro uživatelské rozhraní

Stejně jako v předchozím příkladu se modely zobrazení obvykle spoléhají na modely pro většinu dat a jakoukoli obchodní logiku. Jedná se ale o model zobrazení, který formátuje, převádí a rozšiřuje data jakýmkoli způsobem, který aktuální zobrazení vyžaduje.

Formátování pomocí modelu viewmodel

Už jste viděli příklad formátování pomocí dovolené. Formátování data, kódování znaků a serializace jsou všechny příklady, jak model viewmodel může formátovat data z modelu.

Převod pomocí modelu viewmodel

Model často poskytuje informace nepřímými způsoby. Ale model viewmodel to dokáže opravit. Předpokládejme například, že chcete zobrazit na obrazovce, jestli je zaměstnanec nadřízený. Ale náš Employee model nám to přímo neřekne. Místo toho musíte tuto skutečnost odvodit na základě toho, jestli má tato osoba jiné hlášení. Předpokládejme, že model má tuto vlastnost:

public IList<Employee> DirectReports
{
    get
    {
        ...
    }
}

Pokud je seznam prázdný, můžete odvodit, že to Employee není nadřízený. V tomto případě zahrnuje vlastnostIsSupervisor, EmployeeViewModel která poskytuje tuto logiku:

public bool IsSupervisor => _model.DirectReports.Any();

Rozšíření pomocí modelu viewmodel

Někdy může model poskytnout pouze ID pro související data. Nebo možná budete muset přejít na několik tříd modelů, abyste korelovaly data potřebná pro jednu obrazovku. Model viewmodel poskytuje ideální místo pro provádění těchto úloh. Předpokládejme, že chcete zobrazit všechny projekty, které právě spravuje zaměstnanec. Tato data nejsou součástí Employee třídy modelu. Přístup k němu získáte tak, že se podíváte na CompanyProjects třídu modelu. Naše EmployeeViewModel, jako vždy, zveřejňuje svou práci jako veřejný majetek:

public IEnumerable<string> ActiveProjects => CompanyProjects.All
    .Where(p => p.Owner == _model.Id && p.IsActive)
    .Select(p => p.Name);

Použití průchozích vlastností s modelem viewmodel

Model viewmodel často potřebuje přesně vlastnost, kterou model poskytuje. U těchto vlastností model viewmodel právě předává data:

public string Name
{
    get => _model.Name;
    set => _model.Name = value;
}

Nastavení oboru pro model viewmodel

Model viewmodel můžete použít na libovolné úrovni, kde je zobrazení. Stránka má obvykle model zobrazení, ale může to být i dílčí zobrazení stránky. Jedním z běžných důvodů vnořených modelů zobrazení je, když se na stránce zobrazí ListView stránka. Seznam obsahuje model zobrazení, který představuje kolekci, například EmployeeListViewModel. Každý prvek v seznamu je .EmployeeViewModel

Diagram EmployeeListViewModel s několika podřízenými objekty EmployeeViewModel

Je také běžné mít model zobrazení nejvyšší úrovně, který obsahuje data a stav pro celou aplikaci, ale není přidružen k žádné konkrétní stránce. Takový model zobrazení se běžně používá k údržbě "aktivní" položky. ListView Představte si příklad, který jsme právě popsali. Když uživatel vybere řádek zaměstnance, představuje tento zaměstnanec aktuální položku. Pokud uživatel přejde na stránku podrobností nebo vybere tlačítko panelu nástrojů při výběru daného řádku, měla by být akce nebo zobrazení určené pro daného zaměstnance. Elegantním způsobem zpracování tohoto scénáře je mít ListView.SelectItem data svázaná s vlastností, ke které má také přístup panel nástrojů nebo stránka podrobností. Umístění této vlastnosti na centrální viewmodel funguje dobře.

Určení, kdy se mají opakovaně používat modely viewmodelů se zobrazeními

Jak definujete vztah mezi modelem viewmodel a modelem a mezi modelem viewmodel a zobrazením, je diktován více požadavky aplikace než podle pravidel. Účelem modelu viewmodel je poskytnout zobrazení struktury a dat, která potřebuje. Tento účel by měl vést rozhodnutí o tom, jak velký je rozsah modelu zobrazení.

Modely Viewmodels často úzce odrážejí strukturu třídy modelu a mají relaci 1:1 s danou třídou. Viděli jste příklad dříve s EmployeeViewModel zabalenou a rozšířenou instancí Employee . Není to ale vždy relace 1:1. Pokud je model viewmodel navržený tak, aby poskytoval to, co zobrazení potřebuje, můžete místo toho vytvořit přehled HRDashboardViewModel personálního oddělení, které nemá explicitní vztah k žádnému modelu, ale může používat data z libovolné třídy modelu.

Podobně můžete zjistit, že modely zobrazení a zobrazení mají často relaci 1:1. Ale ne vždy. Pojďme se znovu zamyslet nad řádkem ListView pro každého zaměstnance. Když vyberete jeden z řádků, přejdete na stránku s podrobnostmi o zaměstnancích.

Stránka seznamu má svůj model zobrazení s kolekcí. Jak už bylo navrhnuto dříve, kolekce by mohla být kolekce EmployeeViewModel objektů. A když uživatel vybere řádek, EmployeeViewModel může být instance předána do EmployeeDetailPage . A stránka podrobností by ji mohla použít EmployeeViewModel jako její BindingContext.

Tento scénář může být skvělou příležitostí pro opakované použití modelu zobrazení. Mějte ale na paměti, že modely zobrazení mají poskytovat to, co zobrazení potřebuje. V některých případech můžete chtít samostatné modely zobrazení, i když jsou všechny založené na stejné třídě modelu. V tomto příkladu ListView budou řádky pravděpodobně potřebovat mnohem méně informací než celá stránka podrobností. Pokud načítání dat ze stránky podrobností přidává příliš velkou režii, můžete chtít mít obě EmployeeListRowViewModel i EmployeeDetailViewModel modely, které tyto příslušná zobrazení obsluhují.

Model objektu Viewmodel

Použití základní třídy, která implementuje INotifyPropertyChanged znamená, že nemusíte reimplementovat rozhraní na všech modelech viewmodel. Zvažte aplikaci personálního oddělení, jak je popsáno v předchozí části tohoto školicího modulu. Třída EmployeeViewModel implementovala INotifyPropertyChanged rozhraní a poskytla pomocnou metodu pojmenovanou OnPropertyChanged pro vyvolání PropertyChanged události. Jiné modely zobrazení v projektu, například ty, které popisují zdroje přiřazené zaměstnanci, by také vyžadovaly INotifyPropertyChanged úplnou integraci se zobrazením.

Knihovna MVVM Toolkit, která je součástí sady nástrojů .NET Community Toolkit, je kolekce standardních, samostatných jednoduchých typů, které poskytují počáteční implementaci pro vytváření moderních aplikací pomocí vzoru MVVM.

Místo psaní vlastní základní třídy modelu viewmodel zdědíte z třídy sady nástrojů ObservableObject , která poskytuje vše, co potřebujete pro základní třídu modelu viewmodel. Můžete EmployeeViewModel ho zjednodušit z následujících důvodů:

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));
}

Na následující kód:

using Microsoft.Toolkit.Mvvm.ComponentModel;

public class EmployeeViewModel : ObservableObject
{
    private string _name;

    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }
}

Kód lze dále zjednodušit pomocí zdrojových generátorů poskytovaných MVVM Toolkit. Když třídu partial přidáte [ObservableProperty] do private proměnné, veřejná vlastnost Name se vygeneruje s oznámeními o změně příslušné vlastnosti.

using Microsoft.Toolkit.Mvvm.ComponentModel;

public partial class EmployeeViewModel : ObservableObject
{
    [ObservableProperty]
    private string _name;
}

Sada nástrojů MVVM se distribuuje CommunityToolkit.Mvvm prostřednictvím balíčku NuGet.

Kontrola znalostí

1.

Když použijete model Model-View-ViewModel (MVVM) s .NET MAUI, model, zobrazení a model viewmodel se od sebe úplně nerozdělí. Která volba popisuje jednu společnou závislost mezi částmi MVVM?

2.

Která z největších pravděpodobností bude úzce svázána s platformou a obtížně vytváří testy jednotek pro: model, zobrazení nebo model viewmodel?