Wat is MVVM?
.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).
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
viewmodel
eigenschap:<Label Text="{Binding FormattedVacationBalance}" />
Vervolgens hebt u alleen de
BindingContext
pagina nodig die is ingesteld op een exemplaar vanEmployeeViewModel
.
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 viewmodel
eigenschappen 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 viewmodel
binding 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 viewmodel
werknemer:
<Label Text="{Binding Name}" />
Wanneer de Name
eigenschap in de viewmodel
eigenschap 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.