Vad är MVVM?
.NET MAUI-appar som inte använder Model-View-ViewModel (MVVM) har vanligtvis mer kod i sina kod bakom filer. Kod bakom filerna i .NET MAUI följer det här mönstret: {something}.xaml.cs. De flesta kod i filen bakom koden styr vanligtvis användargränssnittets beteende. Användargränssnittsbeteendet kan innehålla allt som händer med användargränssnittet, till exempel att ändra en färg eller text. Och det kan innehålla allt som händer på grund av användargränssnittet, inklusive knappklickshanterare.
Ett problem med den här metoden är att det är svårt att skriva enhetstester mot kod bakom filer. Kod bakom filer förutsätter ofta ett programtillstånd som skapas genom att parsa XAML eller till och med skapas av andra sidor. Dessa villkor är svåra att hantera i en enhetstestkörare som kanske inte ens körs på en mobil enhet, för att inte tala om med ett användargränssnitt. Enhetstester kan därför sällan testa användargränssnittsbeteenden i dessa filer.
Men det är här MVVM-mönstret är användbart. När det används korrekt löser MVVM-mönstret dessa problem genom att flytta de flesta UI-beteendelogik till enhetstestbara klasser som kallas viewmodels. MVVM-mönstret används oftast med ramverk som stöder databindning. Med .NET MAUI kan du databinda varje UI-element till ett viewmodel
och eliminera eller nästan eliminera kod i en vy eller bakomliggande kod.
Vilka är delarna i ett MVVM-program?
viewmodel
Även om är den unika delen av MVVM-mönstret definierar mönstret även en modelldel och en vydel. Definitionerna av dessa delar överensstämmer med några andra vanliga mönster, till exempel en MVC (Model-View-Controller).
Vad är en modell?
I ett MVVM-program används termmodellen för att ange dina affärsdata och åtgärder. Modellen engagerar sig inte i appens användarpresentation.
En användbar regel för att avgöra vilken kod som hör hemma i modellen är att den ska vara portabel på olika plattformar. Från en mobilapp till ett webbgränssnitt eller till och med ett kommandoradsprogram med samma modell i alla instanser. Det är inte relaterat till hur informationen visas för användaren.
När du tänker på HR-programmet från vårt scenario kan modellen innehålla en Employee
klass och en Department
klass som innehåller data och logik om dessa entiteter. Modellen kan också innehålla saker som en EmployeeRepository
klass som innehåller beständighetslogik. Vissa andra mönster för programvarudesign skulle betrakta saker som lagringsplatser som separata från modellen. Men i samband med MVVM refererar vi ofta till affärslogik eller affärsdata som en del av modellen.
Här är två exempel på en modell i 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() { ... }
...
}
Vad är en vy?
Visningskoden styr saker som direkt interagerar med användaren, till exempel kontroller som knappar och inmatningsfält, samt andra rent visuella element som teman, formatmallar och teckensnitt.
I .NET MAUI behöver du inte skriva någon C#-kod för att generera en vy själv. I stället definierar du ofta dina vyer efter XAML-filer. Det finns situationer som kräver en anpassad användarkontroll, där du skapar en egen vy via kod.
Vad är en viewmodel
?
Det för oss tillbaka till viewmodel
. viewmodel
är mellanhanden mellan vår affärslogik (modell) och våra vyer (UI).
Tänk på vad en viewmodel
kan göra för HR-programmet. Anta att det finns en vy som visar en anställds tillgängliga semestertid och du vill att semestersaldot ska visas som "2 veckor, 3 dagar, 4 timmar". Men affärslogik i modellen ger samma värde som 13,5 dagar, ett decimaltal som representerar det totala antalet dagar under en 8-timmars arbetsdag. Objektmodellen kan se ut som i följande lista:
Modell – klassen
Employee
, som innehåller en metod:public decimal GetVacationBalanceInDays() { //Some math that calculates current vacation balance ... }
ViewModel – en
EmployeeViewModel
klass som har en egenskap som den här: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" } } }
Visa – en XAML-sida som innehåller en enda etikett och en stängningsknapp. Etiketten har en bindning till
viewmodel
egenskapen 's:<Label Text="{Binding FormattedVacationBalance}" />
Sedan behöver
BindingContext
du bara för sidan inställd på en instans avEmployeeViewModel
.
I det här exemplet innehåller modellen affärslogik. Den här logiken är inte bunden till en visuell visning eller enhet. Du kan använda samma logik för en handhållen enhet eller stationär dator. Vyn vet ingenting om affärslogik. Vykontrollerna, som etiketten, vet hur du hämtar text på skärmen, men bryr sig inte om det är ett semestersaldo eller en slumpmässig sträng. De viewmodel
vet lite om båda världarna, så det kan fungera som en mellanhand.
Det som är intressant är hur det viewmodel
åstadkommer att vara en mellanhand: Det exponerar egenskaper som en vy kan binda till. Offentliga egenskaper är det enda sättet att viewmodel
ge data. A viewmodel
kallas så eftersom "modellen" i MVVM representerar strukturen, data och logiken i affärsprocesserna, medan viewmodel
representerar den struktur, data och logik som vyn kräver.
Hur fungerar vyn med viewmodel
?
När du tittar på relationen viewmodel
som har med modellen är det en klass-till-klass-standardrelation. viewmodel
Har en instans av modellen och exponerar aspekter av modellen för vyn via egenskaper. Men hur hämtar och anger en vy egenskaper för viewmodel
? Hur uppdaterar vyn de visuella kontrollerna med nya värden när ändringarna viewmodel
ändras? Svaret är databindning.
Egenskaperna viewmodel
för 's läse vid den tidpunkt då objektet är bundet till vyn. Men bindningen har inget sätt att veta om viewmodel
egenskaperna ändras efter att bindningen har tillämpats på vyn. viewmodel
Om du ändrar sprids inte det nya värdet automatiskt via bindningen till vyn. Om du vill uppdatera från viewmodel
vyn viewmodel
till måste du implementera System.ComponentModel.INotifyPropertyChanged
gränssnittet.
Gränssnittet INotifyPropertyChanged
deklarerar en enskild händelse med namnet PropertyChanged
. Det tar en enda parameter, namnet på egenskapen som ändrade dess värde. Bindningssystemet som används i .NET MAUI förstår det här gränssnittet och lyssnar på den händelsen. När en egenskap ändras på viewmodel
och genererar händelsen meddelar bindningen ändringens mål.
Tänk på hur den här relationen fungerar i HR-programmet med en anställd viewmodel
. Har viewmodel
egenskaper som representerar en medarbetare, till exempel namnet på medarbetaren. Implementerar viewmodel
INotifyPropertyChanged
gränssnittet och när Name
egenskapen ändras genererar händelsen PropertyChanged
, så här:
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));
}
Vyn som beskriver den anställdes information innehåller en etikettkontroll som är bunden till viewmodel
egenskapen 's Name
:
<Label Text="{Binding Name}" />
När egenskapen Name
ändras i viewmodel
PropertyChanged
genereras händelsen med namnet på den egenskapen. Bindningen lyssnar på händelsen och meddelar sedan etiketten att Name
egenskapen har ändrats. Sedan uppdateras etikettens Text
egenskap med det senaste värdet.