Een viewmodel gebruiken

Voltooid

Nadat u meer hebt geleerd over de onderdelen waaruit het MVVM-patroon (Model-View-ViewModel) bestaat, hebt u waarschijnlijk vastgesteld dat het model en de weergave eenvoudig te definiëren waren. Laten we eens kijken hoe u het viewmodel kunt gebruiken om de rol in het patroon beter te definiëren.

Eigenschappen beschikbaar maken voor de gebruikersinterface

Net als in het vorige voorbeeld zijn viewmodels meestal afhankelijk van modellen voor de meeste gegevens en bedrijfslogica. Maar het is het viewmodel dat de gegevens formatteert, converteert en verrijkt op welke manier de huidige weergave vereist.

Opmaken met behulp van een viewmodel

U hebt al een voorbeeld van opmaak met vakantietijd gezien. Datumopmaak, tekencodering en serialisatie zijn allemaal voorbeelden van hoe het viewmodel gegevens van het model kan opmaken.

Converteren met behulp van een viewmodel

Vaak biedt het model informatie op indirecte manieren. Maar het viewmodel kan dat oplossen. Stel dat u op het scherm wilt weergeven of een werknemer een supervisor is. Maar ons Employee model vertelt ons dat niet rechtstreeks. In plaats daarvan moet u dit feit afleiden op basis van of de persoon aan hen rapporteert. Stel dat het model deze eigenschap heeft:

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

Als de lijst leeg is, kunt u afleiden dat dit Employee geen supervisor is. In dit geval EmployeeViewModel bevat u de eigenschap IsSupervisor die die logica biedt:

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

Verrijken met behulp van een viewmodel

Soms kan een model alleen een id voor gerelateerde gegevens opgeven. Of mogelijk moet u naar verschillende modelklassen gaan om de gegevens te correleren die nodig zijn voor één scherm. Het viewmodel biedt ook een ideale plek om deze taken uit te voeren. Stel dat u alle projecten wilt weergeven die een werknemer momenteel beheert. Deze gegevens maken geen deel uit van de Employee modelklasse. U kunt deze openen door naar de CompanyProjects modelklasse te kijken. Onze EmployeeViewModel, zoals altijd, toont zijn werk als een openbare eigenschap:

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

Passthrough-eigenschappen gebruiken met een viewmodel

Vaak heeft een viewmodel exact de eigenschap nodig die het model biedt. Voor deze eigenschappen geeft het viewmodel alleen de gegevens door:

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

Het bereik voor het viewmodel instellen

U kunt een viewmodel gebruiken op elk niveau waar een weergave is. Een pagina heeft meestal een viewmodel, maar kan dus subweergaven van de pagina zijn. Een veelvoorkomende reden voor geneste viewmodels is wanneer de pagina een ListView op de pagina weergeeft. De lijst heeft een viewmodel dat de verzameling vertegenwoordigt, zoals EmployeeListViewModel. Elk element in de lijst is een EmployeeViewModel.

Diagram van een EmployeeListViewModel met verschillende EmployeeViewModel-subobjecten.

Het is ook gebruikelijk om een viewmodel op het hoogste niveau te hebben dat gegevens en status voor de hele toepassing bevat, maar niet is gekoppeld aan een bepaalde pagina. Een dergelijk viewmodel wordt vaak gebruikt voor het onderhouden van het 'actieve' item. Bekijk het ListView voorbeeld dat we zojuist hebben beschreven. Wanneer de gebruiker een rij werknemer selecteert, vertegenwoordigt die werknemer het huidige item. Als de gebruiker naar een detailpagina navigeert of een werkbalkknop selecteert terwijl die rij is geselecteerd, moet de actie of weergave voor die werknemer zijn. Een elegante manier om dit scenario te verwerken, is door de ListView.SelectItem gegevens gebonden te hebben aan een eigenschap waartoe de werkbalk of detailpagina ook toegang heeft. Het plaatsen van die eigenschap op een centraal viewmodel werkt goed.

Bepalen wanneer viewmodels opnieuw moeten worden gebruikt met weergaven

Hoe u de relatie tussen het viewmodel en model en tussen het viewmodel en de weergave definieert, wordt meer bepaald door app-vereisten dan door regels. Het doel van het viewmodel is om de structuur en gegevens te bekijken die het nodig heeft. Dit doel moet leiden tot beslissingen over hoe groot het bereik van een viewmodel is.

Viewmodels weerspiegelen vaak de structuur van een modelklasse en ze hebben een een-op-een-relatie met die klasse. U hebt eerder een voorbeeld gezien met de EmployeeViewModel ingepakte en uitgebreide versie van één Employee exemplaar. Maar het is niet altijd een een-op-een-relatie. Als het viewmodel is ontworpen om te voorzien in wat de weergave nodig heeft, kunt u in plaats daarvan een HRDashboardViewModel overzicht geven van een HR-afdeling, die geen expliciete relatie heeft met een model, maar wel gegevens uit elke modelklasse kan gebruiken.

Op dezelfde manier kan het zijn dat viewmodels en weergaven vaak een een-op-een-relatie hebben. Maar niet altijd. Laten we eens nadenken over een ListView rij voor elke werknemer. Wanneer u een van de rijen selecteert, gaat u naar een pagina met werknemersgegevens.

De lijstpagina heeft het weergavemodel met een verzameling. Zoals eerder is voorgesteld, kan die verzameling een verzameling EmployeeViewModel objecten zijn. En wanneer de gebruiker een rij selecteert, kan het EmployeeViewModel exemplaar worden doorgegeven aan de EmployeeDetailPage. En de detailpagina kan dat EmployeeViewModel als zodanig BindingContextgebruiken.

Dit scenario kan een uitstekende mogelijkheid zijn om viewmodel opnieuw te gebruiken. Houd er echter rekening mee dat viewmodels bedoeld zijn om te voorzien in wat de weergave nodig heeft. In sommige gevallen wilt u mogelijk afzonderlijke viewmodels, zelfs als ze allemaal zijn gebaseerd op dezelfde modelklasse. In dit voorbeeld hebben de ListView rijen waarschijnlijk veel minder informatie nodig dan de volledige detailpagina. Als het ophalen van de gegevens van de detailpagina te veel overhead toevoegt, wilt u mogelijk beide EmployeeListRowViewModel modellen EmployeeDetailViewModel hebben die deze respectieve weergaven gebruiken.

Viewmodel-objectmodel

Als u een basisklasse gebruikt die wordt geïmplementeerd INotifyPropertyChanged , betekent dit dat u de interface niet opnieuw hoeft in te vullen in elk viewmodel. Bekijk de HR-toepassing zoals beschreven in het vorige deel van deze trainingsmodule. De EmployeeViewModel klasse heeft de INotifyPropertyChanged interface geïmplementeerd en een helpermethode geleverd met de naam OnPropertyChanged om de PropertyChanged gebeurtenis te genereren. Andere viewmodels in het project, zoals weergavemodellen die resources beschrijven die zijn toegewezen aan een werknemer, moeten INotifyPropertyChanged ook volledig worden geïntegreerd met een weergave.

De MVVM Toolkit-bibliotheek , onderdeel van de .NET Community Toolkit, is een verzameling standaard, zelfstandige, lichtgewicht typen die een start-implementatie bieden voor het bouwen van moderne apps met behulp van het MVVM-patroon.

In plaats van uw eigen viewmodel-basisklasse te schrijven, neemt u over van de klasse van ObservableObject de toolkit, die alles biedt wat u nodig hebt voor een viewmodel-basisklasse. De EmployeeViewModel kan worden vereenvoudigd van:

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

In de volgende code:

using Microsoft.Toolkit.Mvvm.ComponentModel;

public class EmployeeViewModel : ObservableObject
{
    private string _name;

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

De code kan verder worden vereenvoudigd met behulp van brongeneratoren die worden geleverd door de MVVM Toolkit. Door de klasse partial te maken en de [ObservableProperty] variabele toe te private voegen, wordt de openbare eigenschap Name gegenereerd met de juiste meldingen over eigenschappenwijziging.

using Microsoft.Toolkit.Mvvm.ComponentModel;

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

De MVVM Toolkit wordt gedistribueerd via het CommunityToolkit.Mvvm NuGet-pakket.