Wat is MVVM?

Voltooid

.NET MAUI-apps die geen MVVM (Model-View-ViewModel) gebruiken, hebben over het algemeen meer code in hun code-behind-bestanden . De code-behind-bestanden in .NET MAUI volgen dit patroon: {something}.xaml.cs. De meeste code in het code-behind-bestand bepaalt meestal het gedrag van de gebruikersinterface (UI). Ui-gedrag kan alles bevatten wat er met de gebruikersinterface gebeurt, zoals het wijzigen van een kleur of tekst. En het kan alles bevatten wat er gebeurt vanwege de gebruikersinterface, inclusief knop-klikhandlers.

Een probleem met deze aanpak is dat het moeilijk is om eenheidstests te schrijven op basis van code-behind-bestanden. Code-behind-bestanden gaan vaak uit van een toepassingsstatus die is gemaakt door XAML te parseren of zelfs door andere pagina's te maken. Deze omstandigheden zijn moeilijk te verwerken in een eenheidstestloper die mogelijk niet eens op een mobiel apparaat wordt uitgevoerd, laat staan met een gebruikersinterface. Eenheidstests kunnen daarom zelden het gedrag van de gebruikersinterface in deze bestanden testen.

Maar hier is waar het MVVM-patroon nuttig is. Wanneer dit correct wordt gebruikt, lost het MVVM-patroon deze problemen op door de meeste ui-gedragslogica te verplaatsen naar eenheidstestbare klassen die viewmodels worden genoemd. Het MVVM-patroon wordt meestal gebruikt met frameworks die gegevensbinding ondersteunen. Met .NET MAUI kunt u elk UI-element koppelen aan een viewmodel en bijna alle code in een weergave of code-behind elimineren of bijna elimineren.

Wat zijn de onderdelen van een MVVM-toepassing?

Hoewel het viewmodel unieke deel van het MVVM-patroon is, definieert het patroon ook een modelonderdeel en een weergaveonderdeel . De definities van deze onderdelen zijn consistent met enkele andere veelvoorkomende patronen, zoals een MVC (Model-View-Controller).

Wat is een model?

In een MVVM-toepassing wordt het termmodel gebruikt om uw bedrijfsgegevens en -activiteiten aan te geven. Het model heeft geen betrekking op de gebruikerspresentatie van de app.

Een nuttige regel voor het bepalen van welke code deel uitmaakt van het model is dat deze overdraagbaar moet zijn op verschillende platforms. Van een mobiele app naar een webinterface of zelfs een opdrachtregelprogramma, met hetzelfde model in alle exemplaren. Het is niet gerelateerd aan de weergave van de informatie aan de gebruiker.

Wanneer u nadenkt over de HR-toepassing uit ons scenario, kan het model een Employee klasse en een Department klasse bevatten die gegevens en logica over deze entiteiten bevat. Het model kan ook zaken bevatten als een EmployeeRepository klasse die persistentielogica bevat. Sommige andere softwareontwerppatronen beschouwen zaken als opslagplaatsen als gescheiden van het model. Maar in de context van MVVM verwijzen we vaak naar bedrijfslogica of zakelijke gegevens als onderdeel van het model.

Hier volgen twee voorbeelden van een model in 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() { ... }
    ...
}

Wat is een weergave?

De weergavecode bepaalt dingen die rechtstreeks met de gebruiker communiceren, zoals besturingselementen zoals knoppen en invoervelden, evenals andere puur visuele elementen, zoals thema's, stijlen en lettertypen.

In .NET MAUI hoeft u geen C#-code te schrijven om zelf een weergave te genereren. In plaats daarvan definieert u uw weergaven vaak door XAML-bestanden. Er zijn situaties waarin een aangepast gebruikersbeheer wordt aangeroepen, waarin u uw eigen weergave maakt via code.

Wat is een viewmodel?

Dat brengt ons terug naar de viewmodel. Dit viewmodel is de intermediair tussen onze bedrijfslogica (model) en onze weergaven (UI).

Een diagram dat laat zien hoe een viewmodel een tussenpersoon is tussen een model en een weergave.

Denk na over wat een viewmodel kan doen voor de HR-toepassing. Stel dat er een weergave is waarin de beschikbare vakantietijd van een werknemer wordt weergegeven en u het vakantiesaldo wilt weergeven als '2 weken, 3 dagen, 4 uur'. Maar de bedrijfslogica in het model biedt dezelfde waarde als 13,5 dagen, een decimaal getal dat het totale aantal dagen in een werkdag van 8 uur vertegenwoordigt. Het objectmodel kan er als volgt uitzien:

  • Model : de Employee klasse, die een methode bevat:

    public decimal GetVacationBalanceInDays()
    {
        //Some math that calculates current vacation balance
        ...
    }
    
  • ViewModel : een EmployeeViewModel klasse met een eigenschap zoals deze:

    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"
            }
        }
    }
    
  • Weergave : een XAML-pagina met één label en een knop Sluiten. Het label heeft een binding met de eigenschap van de viewmodeleigenschap:

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

    Vervolgens hebt u alleen de BindingContext pagina nodig die is ingesteld op een exemplaar van EmployeeViewModel.

In dit voorbeeld bevat het model de bedrijfslogica. Deze logica is niet gebonden aan een visuele weergave of een apparaat. U kunt dezelfde logica gebruiken voor een handheld-apparaat of desktopcomputer. De weergave kent niets van de bedrijfslogica. De weergavebesturingselementen, zoals het label, weten hoe u tekst op het scherm kunt ophalen, maar het maakt niet uit of het een vakantiebalans of een willekeurige tekenreeks is. Het viewmodel kent een beetje van beide werelden, zodat het als intermediair kan fungeren.

Wat interessant is, is hoe de viewmodel resultaten een tussenpersoon zijn: het toont eigenschappen waarop een weergave kan binden. Openbare eigenschappen zijn de enige manier waarop een viewmodel gegevens levert. A viewmodel wordt genoemd omdat het "model" in MVVM de structuur, gegevens en logica van de bedrijfsprocessen vertegenwoordigt, terwijl de viewmodel structuur, gegevens en logica die de weergave vereist vertegenwoordigt.

Hoe werkt de weergave met de viewmodel?

Wanneer u de relatie bekijkt die het viewmodel model heeft, is het een standaard-klasse-naar-klasse-relatie. Het viewmodel heeft een exemplaar van het model en toont aspecten van het model aan de weergave via eigenschappen. Maar hoe haalt een weergave eigenschappen op en stelt u deze in op de viewmodel? Wanneer de viewmodel wijzigingen zijn doorgevoerd, hoe werkt de weergave de besturingselementen van de visual bij met nieuwe waarden? Het antwoord is gegevensbinding.

De viewmodeleigenschappen van de objecten worden gelezen op het moment dat het object is gebonden aan de weergave. Maar de binding kan niet weten of de eigenschappen van de viewmodelbinding veranderen nadat de binding is toegepast op de weergave. Als u de viewmodel nieuwe waarde wijzigt, wordt de nieuwe waarde niet automatisch doorgegeven aan de weergave. Als u wilt bijwerken van de viewmodel weergave naar de weergave, moet de viewmodel interface worden System.ComponentModel.INotifyPropertyChanged geïmplementeerd.

De INotifyPropertyChanged interface declareert één gebeurtenis met de naam PropertyChanged. Er wordt één parameter gebruikt, de naam van de eigenschap die de waarde heeft gewijzigd. Het bindingssysteem dat in .NET MAUI wordt gebruikt, begrijpt deze interface en luistert naar die gebeurtenis. Wanneer een eigenschap op de viewmodel gebeurtenis verandert en de gebeurtenis genereert, geeft de binding een bericht over het doel van de wijziging.

Denk na over hoe deze relatie werkt in de HR-toepassing met een werknemer viewmodel. De viewmodel eigenschap heeft eigenschappen die een werknemer vertegenwoordigen, zoals de naam van de werknemer. De viewmodel interface wordt geïmplementeerd INotifyPropertyChanged en wanneer de Name eigenschap wordt gewijzigd, wordt de PropertyChanged gebeurtenis gegenereerd, zoals deze:

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

De weergave waarin de details van de werknemer worden beschreven, bevat een labelbesturingselement dat is gebonden aan de eigenschap van Name de viewmodelwerknemer:

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

Wanneer de Name eigenschap in de viewmodeleigenschap verandert, wordt de PropertyChanged gebeurtenis gegenereerd met de naam van die eigenschap. De binding luistert naar de gebeurtenis en meldt vervolgens het label dat de Name eigenschap heeft gewijzigd. Vervolgens wordt de eigenschap van Text het label bijgewerkt met de meest recente waarde.

Kennis testen

1.

Een ontwikkelaar werkt aan een .NET MAUI-toepassing en wil het MVVM-patroon implementeren. Ze maken een model voor zakelijke gegevens en bewerkingen en een weergave voor gebruikersinteractie. Wat moeten ze maken om als intermediair tussen het model en de weergave te fungeren?

2.

Een team ontwikkelt een mobiele toepassing met behulp van .NET MAUI en wil ervoor zorgen dat hun bedrijfslogica over verschillende platforms kan worden gebruikt. Waar moeten ze deze bedrijfslogica in het MVVM-patroon plaatsen?